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]

Cell multi-arch: combined patch


Hello,

if you prefer a single patch over a patch series, here's the 
equivalent patch to the 18 Cell multi-arch patches.

Bye,
Ulrich


diff -urNp gdb-orig/gdb/arch-utils.c gdb-head/gdb/arch-utils.c
--- gdb-orig/gdb/arch-utils.c	2008-09-05 13:42:04.000000000 +0200
+++ gdb-head/gdb/arch-utils.c	2008-09-07 23:21:58.985137309 +0200
@@ -326,15 +326,24 @@ set_endian (char *ignore_args, int from_
 }
 
 /* Given SELECTED, a currently selected BFD architecture, and
-   FROM_TARGET, a BFD architecture reported by the target description,
-   return what architecture to use.  Either may be NULL; if both are
-   specified, we use the more specific.  If the two are obviously
-   incompatible, warn the user.  */
+   TARGET_DESC, the current target description, return what
+   architecture to use.
+
+   SELECTED may be NULL, in which case we return the architecture
+   associated with TARGET_DESC.  If SELECTED specifies a variant
+   of the architecture associtated with TARGET_DESC, return the
+   more specific of the two.
+
+   If SELECTED is a different architecture, but it is accepted as
+   compatible by the target, we can use the target architecture.
+
+   If SELECTED is obviously incompatible, warn the user.  */
 
 static const struct bfd_arch_info *
-choose_architecture_for_target (const struct bfd_arch_info *selected,
-				const struct bfd_arch_info *from_target)
+choose_architecture_for_target (const struct target_desc *target_desc,
+				const struct bfd_arch_info *selected)
 {
+  const struct bfd_arch_info *from_target = tdesc_architecture (target_desc);
   const struct bfd_arch_info *compat1, *compat2;
 
   if (selected == NULL)
@@ -364,6 +373,11 @@ choose_architecture_for_target (const st
 
   if (compat1 == NULL && compat2 == NULL)
     {
+      /* BFD considers the architectures incompatible.  Check our target
+	 description whether it accepts SELECTED as compatible anyway.  */
+      if (tdesc_compatible_p (target_desc, selected))
+	return from_target;
+
       warning (_("Selected architecture %s is not compatible "
 		 "with reported target architecture %s"),
 	       selected->printable_name, from_target->printable_name);
@@ -692,7 +706,7 @@ gdbarch_info_fill (struct gdbarch_info *
   /* From the target.  */
   if (info->target_desc != NULL)
     info->bfd_arch_info = choose_architecture_for_target
-      (info->bfd_arch_info, tdesc_architecture (info->target_desc));
+			   (info->target_desc, info->bfd_arch_info);
   /* From the default.  */
   if (info->bfd_arch_info == NULL)
     info->bfd_arch_info = default_bfd_arch;
@@ -720,6 +734,27 @@ gdbarch_info_fill (struct gdbarch_info *
   gdb_assert (info->bfd_arch_info != NULL);
 }
 
+
+/* restore_current_gdbarch() will be used by the cleanup machinery
+   to restore the current_gdbarch value saved in a call to
+   save_current_gdbarch().  */
+
+static void
+restore_current_gdbarch (void *arg)
+{
+  current_gdbarch = arg;
+}
+
+/* Save the value of current so that it may be restored by a
+   later call to do_cleanups().  Returns the struct cleanup pointer
+   needed for later doing the cleanup.  */
+
+struct cleanup *
+save_current_gdbarch (void)
+{
+  return make_cleanup (restore_current_gdbarch, current_gdbarch);
+}
+
 /* */
 
 extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
diff -urNp gdb-orig/gdb/arch-utils.h gdb-head/gdb/arch-utils.h
--- gdb-orig/gdb/arch-utils.h	2008-09-05 13:42:04.000000000 +0200
+++ gdb-head/gdb/arch-utils.h	2008-09-07 23:21:53.339150286 +0200
@@ -139,4 +139,9 @@ extern void gdbarch_info_fill (struct gd
 
 extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
 
+/* Save value of current_gdbarch so that it may be restored by
+   a later call to do_cleanups().  Returns the struct cleanup
+   pointer needed for later doing the cleanup.  */
+struct cleanup *save_current_gdbarch (void);
+
 #endif
diff -urNp gdb-orig/gdb/avr-tdep.c gdb-head/gdb/avr-tdep.c
--- gdb-orig/gdb/avr-tdep.c	2008-09-02 23:19:50.000000000 +0200
+++ gdb-head/gdb/avr-tdep.c	2008-09-07 23:21:57.514214710 +0200
@@ -278,7 +278,8 @@ avr_convert_saddr_to_raw (CORE_ADDR x)
 /* Convert from address to pointer and vice-versa. */
 
 static void
-avr_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
+avr_address_to_pointer (struct gdbarch *gdbarch,
+			struct type *type, gdb_byte *buf, CORE_ADDR addr)
 {
   /* Is it a code address?  */
   if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
@@ -296,7 +297,8 @@ avr_address_to_pointer (struct type *typ
 }
 
 static CORE_ADDR
-avr_pointer_to_address (struct type *type, const gdb_byte *buf)
+avr_pointer_to_address (struct gdbarch *gdbarch,
+			struct type *type, const gdb_byte *buf)
 {
   CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
 
diff -urNp gdb-orig/gdb/breakpoint.c gdb-head/gdb/breakpoint.c
--- gdb-orig/gdb/breakpoint.c	2008-09-05 13:34:13.000000000 +0200
+++ gdb-head/gdb/breakpoint.c	2008-09-07 23:21:56.149145164 +0200
@@ -1162,7 +1162,7 @@ Note: automatically using hardware break
 		  bpt->overlay_target_info = bpt->target_info;
 		  bpt->overlay_target_info.placed_address = addr;
 		  val = target_insert_breakpoint (&bpt->overlay_target_info);
-		  if (val != 0)
+		  if (val > 0)
 		    fprintf_unfiltered (tmp_error_stream, 
 					"Overlay breakpoint %d failed: in ROM?", 
 					bpt->owner->number);
@@ -1185,6 +1185,14 @@ Note: automatically using hardware break
 	    }
 	}
 
+      if (val < 0)
+	{
+	  /* The target could not insert the breakpoint right away due
+	     to a temporary issue.  No error, but do not mark the bp
+	     as 'inserted'.  */
+	  return 0;
+	}
+
       if (val)
 	{
 	  /* Can't set the breakpoint.  */
@@ -1666,6 +1674,14 @@ remove_breakpoint (struct bp_location *b
 	    }
 	}
 
+      if (val < 0)
+	{
+	  /* The target could not remove the breakpoint right away due
+	     to a temporary issue.  No error, but keep the bp marked
+	     as 'inserted'.  */
+	  return 0;
+	}
+
       /* In some cases, we might not be able to remove a breakpoint
 	 in a shared library that has already been removed, but we
 	 have not yet processed the shlib unload event.  */
@@ -7664,6 +7680,37 @@ breakpoint_re_set (void)
   
   create_overlay_event_breakpoint ("_ovly_debug_event");
 }
+
+/* Update breakpoint location list after an object file was relocated.  */
+void
+breakpoint_relocate (struct objfile *objfile, struct section_offsets *delta)
+{
+  struct bp_location *b;
+  struct obj_section *s;
+
+  /* Update the breakpoint addresses so that breakpoint_re_set has a chance
+     to identify the previous locations (to carry over enabled state).  */
+  ALL_BP_LOCATIONS (b)
+    {
+      if (b->inserted || b->loc_type == bp_loc_other)
+	continue;
+
+      ALL_OBJFILE_OSECTIONS (objfile, s)
+	{
+	  CORE_ADDR offset = ANOFFSET (delta, s->the_bfd_section->index);
+
+	  if (b->address >= obj_section_addr (s) - offset
+	      && b->address < obj_section_endaddr (s) - offset)
+	    {
+	      b->address += offset;
+	      break;
+	    }
+	}
+    }
+
+  /* Now reset all breakpoints.  */
+  breakpoint_re_set ();
+}
 
 /* Reset the thread number of this breakpoint:
 
diff -urNp gdb-orig/gdb/breakpoint.h gdb-head/gdb/breakpoint.h
--- gdb-orig/gdb/breakpoint.h	2008-09-05 13:34:13.000000000 +0200
+++ gdb-head/gdb/breakpoint.h	2008-09-07 23:21:56.156144159 +0200
@@ -689,6 +689,8 @@ extern int breakpoint_thread_match (CORE
 
 extern void until_break_command (char *, int, int);
 
+extern void breakpoint_relocate (struct objfile *, struct section_offsets *);
+
 extern void breakpoint_re_set (void);
 
 extern void breakpoint_re_set_thread (struct breakpoint *);
diff -urNp gdb-orig/gdb/cli/cli-dump.c gdb-head/gdb/cli/cli-dump.c
--- gdb-orig/gdb/cli/cli-dump.c	2008-01-01 23:53:14.000000000 +0100
+++ gdb-head/gdb/cli/cli-dump.c	2008-09-07 23:21:56.850177282 +0200
@@ -441,7 +441,7 @@ add_dump_command (char *name, void (*fun
 
 /* Opaque data for restore_section_callback. */
 struct callback_data {
-  long load_offset;
+  CORE_ADDR load_offset;
   CORE_ADDR load_start;
   CORE_ADDR load_end;
 };
@@ -546,8 +546,8 @@ restore_binary_file (char *filename, str
   printf_filtered 
     ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n", 
      filename, 
-     (unsigned long) data->load_start + data->load_offset, 
-     (unsigned long) data->load_start + data->load_offset + len);
+     (unsigned long) (data->load_start + data->load_offset),
+     (unsigned long) (data->load_start + data->load_offset + len));
 
   /* Now set the file pos to the requested load start pos.  */
   if (fseek (file, data->load_start, SEEK_SET) != 0)
@@ -597,7 +597,7 @@ restore_command (char *args, int from_tt
       /* Parse offset (optional). */
       if (args != NULL && *args != '\0')
       data.load_offset = 
-	parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
+	parse_and_eval_address (scan_expression_with_cleanup (&args, NULL));
       if (args != NULL && *args != '\0')
 	{
 	  /* Parse start address (optional). */
diff -urNp gdb-orig/gdb/configure.tgt gdb-head/gdb/configure.tgt
--- gdb-orig/gdb/configure.tgt	2008-05-11 22:28:33.000000000 +0200
+++ gdb-head/gdb/configure.tgt	2008-09-07 23:22:00.489186905 +0200
@@ -349,7 +349,8 @@ powerpc-*-aix* | rs6000-*-*)
 powerpc-*-linux* | powerpc64-*-linux*)
 	# Target: PowerPC running Linux
 	gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \
-			solib.o solib-svr4.o corelow.o symfile-mem.o"
+			solib.o solib-svr4.o solib-spu.o spu-multiarch.o \
+			corelow.o symfile-mem.o"
 	gdb_sim=../sim/ppc/libsim.a
 	build_gdbserver=yes
 	;;
diff -urNp gdb-orig/gdb/corelow.c gdb-head/gdb/corelow.c
--- gdb-orig/gdb/corelow.c	2008-08-21 21:44:31.000000000 +0200
+++ gdb-head/gdb/corelow.c	2008-09-07 23:21:58.265240652 +0200
@@ -504,6 +504,33 @@ core_files_info (struct target_ops *t)
   print_section_info (t, core_bfd);
 }
 
+struct spuid_list
+{
+  gdb_byte *buf;
+  ULONGEST offset;
+  LONGEST len;
+  ULONGEST pos;
+  ULONGEST written;
+};
+
+static void
+add_to_spuid_list (bfd *abfd, asection *asect, void *list_p)
+{
+  struct spuid_list *list = list_p;
+  int fd, pos = 0;
+
+  sscanf (bfd_section_name (abfd, asect), "SPU/%d/regs%n", &fd, &pos);
+  if (pos == 0)
+    return;
+
+  if (list->pos >= list->offset && list->pos + 4 <= list->offset + list->len)
+    {
+      store_unsigned_integer (list->buf + list->pos - list->offset, 4, fd);
+      list->written += 4;
+    }
+  list->pos += 4;
+}
+
 static LONGEST
 core_xfer_partial (struct target_ops *ops, enum target_object object,
 		   const char *annex, gdb_byte *readbuf,
@@ -596,6 +623,53 @@ core_xfer_partial (struct target_ops *op
 	}
       /* FALL THROUGH */
 
+    case TARGET_OBJECT_SPU:
+      if (readbuf && annex)
+	{
+	  /* When the SPU contexts are stored in core file, BFD
+	     represents this with a fake section called "SPU/<annex>".  */
+
+	  struct bfd_section *section;
+	  bfd_size_type size;
+	  char *contents;
+
+	  char sectionstr[100];
+	  xsnprintf (sectionstr, sizeof sectionstr, "SPU/%s", annex);
+
+	  section = bfd_get_section_by_name (core_bfd, sectionstr);
+	  if (section == NULL)
+	    return -1;
+
+	  size = bfd_section_size (core_bfd, section);
+	  if (offset >= size)
+	    return 0;
+	  size -= offset;
+	  if (size > len)
+	    size = len;
+	  if (size > 0
+	      && !bfd_get_section_contents (core_bfd, section, readbuf,
+					    (file_ptr) offset, size))
+	    {
+	      warning (_("Couldn't read SPU section in core file."));
+	      return -1;
+	    }
+
+	  return size;
+	}
+      else if (readbuf)
+	{
+	  /* NULL annex requests list of all present spuids.  */
+	  struct spuid_list list;
+	  list.buf = readbuf;
+	  list.offset = offset;
+	  list.len = len;
+	  list.pos = 0;
+	  list.written = 0;
+	  bfd_map_over_sections (core_bfd, add_to_spuid_list, &list);
+	  return list.written;
+	}
+      return -1;
+
     default:
       if (ops->beneath != NULL)
 	return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
@@ -635,8 +709,8 @@ core_file_thread_alive (ptid_t tid)
 static const struct target_desc *
 core_read_description (struct target_ops *target)
 {
-  if (gdbarch_core_read_description_p (current_gdbarch))
-    return gdbarch_core_read_description (current_gdbarch, target, core_bfd);
+  if (core_gdbarch && gdbarch_core_read_description_p (core_gdbarch))
+    return gdbarch_core_read_description (core_gdbarch, target, core_bfd);
 
   return NULL;
 }
diff -urNp gdb-orig/gdb/doc/gdb.texinfo gdb-head/gdb/doc/gdb.texinfo
--- gdb-orig/gdb/doc/gdb.texinfo	2008-09-04 02:50:13.000000000 +0200
+++ gdb-head/gdb/doc/gdb.texinfo	2008-09-07 23:22:04.642255199 +0200
@@ -16431,6 +16431,33 @@ and local store addresses and transfer s
 
 @end table
  
+When @value{GDBN} is debugging a combined PowerPC/SPU application
+on the Cell Broadband Engine, it provides in addition the following
+special commands:
+
+@table @code
+@item set spu stop-on-load @var{arg}
+@kindex set spu
+Set whether to stop for new SPE threads.  When set to @code{on}, @value{GDBN}
+will give control to the user when a new SPE threads enters its @code{main}
+function.
+
+@item show spu stop-on-load
+@kindex show spu
+Show whether to stop for new SPE threads.
+
+@item set spu auto-flush-cache @var{arg}
+Set whether to automatically flush the software-managed cache.  When set to
+@code{on}, @value{GDBN} will automatically cause the SPE software-managed
+cache to be flushed whenever SPE execution stops.  This provides a consistent
+view of PowerPC memory that is accessed via the cache.  If an application
+does not use the software-managed cache, this option has no effect.
+
+@item show spu auto-flush-cache
+Show whether to automatically flush the software-managed cache.
+
+@end table
+
 @node PowerPC
 @subsection PowerPC
 @cindex PowerPC architecture
@@ -27586,6 +27613,7 @@ are explained further below.
 <!DOCTYPE target SYSTEM "gdb-target.dtd">
 <target version="1.0">
   @r{[}@var{architecture}@r{]}
+  @r{[}@var{compatible}@dots{}@r{]}
   @r{[}@var{feature}@dots{}@r{]}
 </target>
 @end smallexample
@@ -27641,6 +27669,26 @@ An @samp{<architecture>} element has thi
 accepted by @code{set architecture} (@pxref{Targets, ,Specifying a
 Debugging Target}).
 
+@subsection Compatible Architecture
+@cindex <compatible>
+
+A @samp{<compatible>} element has this form:
+
+@smallexample
+  <compatible>@var{arch}</compatible>
+@end smallexample
+
+@var{arch} is an architecture name from the same selection
+accepted by @code{set architecture} (@pxref{Targets, ,Specifying a
+Debugging Target}).
+
+A @samp{<compatible>} element is used to specify that the target
+is able to run binaries in some other than the main target architecture
+given by the @samp{<architecture>} element.  For example, on the
+Cell Broadband Engine, the main architecture is @code{powerpc:common}
+or @code{powerpc:common64}, but the system is able to run binaries
+in the @code{spu} architecture as well.
+
 @subsection Features
 @cindex <feature>
 
diff -urNp gdb-orig/gdb/features/Makefile gdb-head/gdb/features/Makefile
--- gdb-orig/gdb/features/Makefile	2008-08-21 21:44:33.000000000 +0200
+++ gdb-head/gdb/features/Makefile	2008-09-07 23:21:59.673171293 +0200
@@ -34,7 +34,7 @@
 WHICH = arm-with-iwmmxt mips-linux mips64-linux \
 	rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
 	rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
-	rs6000/powerpc-vsx64l
+	rs6000/powerpc-vsx64l rs6000/powerpc-cell32l rs6000/powerpc-cell64l
 
 # Record which registers should be sent to GDB by default after stop.
 arm-with-iwmmxt-expedite = r11,sp,pc
@@ -42,10 +42,12 @@ mips-linux-expedite = r29,pc
 mips64-linux-expedite = r29,pc
 rs6000/powerpc-32l-expedite = r1,pc
 rs6000/powerpc-altivec32l-expedite = r1,pc
+rs6000/powerpc-cell32l-expedite = r1,pc,r0,orig_r3,r4
 rs6000/powerpc-vsx32l-expedite = r1,pc
 rs6000/powerpc-e500l-expedite = r1,pc
 rs6000/powerpc-64l-expedite = r1,pc
 rs6000/powerpc-altivec64l-expedite = r1,pc
+rs6000/powerpc-cell64l-expedite = r1,pc,r0,orig_r3,r4
 rs6000/powerpc-vsx64l-expedite = r1,pc
 
 
diff -urNp gdb-orig/gdb/features/rs6000/powerpc-cell32l.c gdb-head/gdb/features/rs6000/powerpc-cell32l.c
--- gdb-orig/gdb/features/rs6000/powerpc-cell32l.c	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/features/rs6000/powerpc-cell32l.c	2008-09-07 23:21:59.681170145 +0200
@@ -0,0 +1,170 @@
+/* THIS FILE IS GENERATED.  Original: powerpc-cell32l.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_powerpc_cell32l;
+static void
+initialize_tdesc_powerpc_cell32l (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct type *field_type, *type;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("powerpc:common"));
+
+  tdesc_add_compatible (result, bfd_scan_arch ("spu:256K"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.core");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "pc", 64, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "msr", 65, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "cr", 66, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "lr", 67, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "ctr", 68, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "xer", 69, 1, NULL, 32, "uint32");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.fpu");
+  tdesc_create_reg (feature, "f0", 32, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f1", 33, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f2", 34, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f3", 35, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f4", 36, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f5", 37, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f6", 38, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f7", 39, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f8", 40, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f9", 41, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f10", 42, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f11", 43, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f12", 44, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f13", 45, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f14", 46, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f15", 47, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f16", 48, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f17", 49, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f18", 50, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f19", 51, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f20", 52, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f21", 53, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f22", 54, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f23", 55, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f24", 56, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f25", 57, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f26", 58, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f27", 59, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f28", 60, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f29", 61, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f30", 62, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f31", 63, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fpscr", 70, 1, "float", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux");
+  tdesc_create_reg (feature, "orig_r3", 71, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "trap", 72, 1, NULL, 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.altivec");
+  field_type = tdesc_named_type (feature, "ieee_single");
+  type = init_vector_type (field_type, 4);
+  TYPE_NAME (type) = xstrdup ("v4f");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int32");
+  type = init_vector_type (field_type, 4);
+  TYPE_NAME (type) = xstrdup ("v4i32");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int16");
+  type = init_vector_type (field_type, 8);
+  TYPE_NAME (type) = xstrdup ("v8i16");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int8");
+  type = init_vector_type (field_type, 16);
+  TYPE_NAME (type) = xstrdup ("v16i8");
+  tdesc_record_type (feature, type);
+
+  type = init_composite_type (NULL, TYPE_CODE_UNION);
+  TYPE_NAME (type) = xstrdup ("vec128");
+  field_type = tdesc_named_type (feature, "uint128");
+  append_composite_type_field (type, xstrdup ("uint128"), field_type);
+  field_type = tdesc_named_type (feature, "v4f");
+  append_composite_type_field (type, xstrdup ("v4_float"), field_type);
+  field_type = tdesc_named_type (feature, "v4i32");
+  append_composite_type_field (type, xstrdup ("v4_int32"), field_type);
+  field_type = tdesc_named_type (feature, "v8i16");
+  append_composite_type_field (type, xstrdup ("v8_int16"), field_type);
+  field_type = tdesc_named_type (feature, "v16i8");
+  append_composite_type_field (type, xstrdup ("v16_int8"), field_type);
+  TYPE_VECTOR (type) = 1;
+  tdesc_record_type (feature, type);
+
+  tdesc_create_reg (feature, "vr0", 73, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr1", 74, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr2", 75, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr3", 76, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr4", 77, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr5", 78, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr6", 79, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr7", 80, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr8", 81, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr9", 82, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr10", 83, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr11", 84, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr12", 85, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr13", 86, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr14", 87, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr15", 88, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr16", 89, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr17", 90, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr18", 91, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr19", 92, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr20", 93, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr21", 94, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr22", 95, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr23", 96, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr24", 97, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr25", 98, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr26", 99, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr27", 100, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr28", 101, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr29", 102, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr30", 103, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr31", 104, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vscr", 105, 1, "vector", 32, "int");
+  tdesc_create_reg (feature, "vrsave", 106, 1, "vector", 32, "int");
+
+  tdesc_powerpc_cell32l = result;
+}
diff -urNp gdb-orig/gdb/features/rs6000/powerpc-cell32l.xml gdb-head/gdb/features/rs6000/powerpc-cell32l.xml
--- gdb-orig/gdb/features/rs6000/powerpc-cell32l.xml	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/features/rs6000/powerpc-cell32l.xml	2008-09-07 23:21:59.685169570 +0200
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- Cell/B.E. architecture.  Identical to the PowerPC 32-bit Linux UISA,
+     but adds support for the SPU as compatible architecture.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common</architecture>
+  <compatible>spu</compatible>
+  <xi:include href="power-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+</target>
diff -urNp gdb-orig/gdb/features/rs6000/powerpc-cell64l.c gdb-head/gdb/features/rs6000/powerpc-cell64l.c
--- gdb-orig/gdb/features/rs6000/powerpc-cell64l.c	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/features/rs6000/powerpc-cell64l.c	2008-09-07 23:21:59.691168709 +0200
@@ -0,0 +1,170 @@
+/* THIS FILE IS GENERATED.  Original: powerpc-cell64l.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_powerpc_cell64l;
+static void
+initialize_tdesc_powerpc_cell64l (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct type *field_type, *type;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("powerpc:common64"));
+
+  tdesc_add_compatible (result, bfd_scan_arch ("spu:256K"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.core");
+  tdesc_create_reg (feature, "r0", 0, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r1", 1, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r2", 2, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r3", 3, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r4", 4, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r5", 5, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r6", 6, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r7", 7, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r8", 8, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r9", 9, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r10", 10, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r11", 11, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r12", 12, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r13", 13, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r14", 14, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r15", 15, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r16", 16, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r17", 17, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r18", 18, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r19", 19, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r20", 20, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r21", 21, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r22", 22, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r23", 23, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r24", 24, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r25", 25, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r26", 26, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r27", 27, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r28", 28, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r29", 29, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r30", 30, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "r31", 31, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "pc", 64, 1, NULL, 64, "code_ptr");
+  tdesc_create_reg (feature, "msr", 65, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "cr", 66, 1, NULL, 32, "uint32");
+  tdesc_create_reg (feature, "lr", 67, 1, NULL, 64, "code_ptr");
+  tdesc_create_reg (feature, "ctr", 68, 1, NULL, 64, "uint64");
+  tdesc_create_reg (feature, "xer", 69, 1, NULL, 32, "uint32");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.fpu");
+  tdesc_create_reg (feature, "f0", 32, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f1", 33, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f2", 34, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f3", 35, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f4", 36, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f5", 37, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f6", 38, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f7", 39, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f8", 40, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f9", 41, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f10", 42, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f11", 43, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f12", 44, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f13", 45, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f14", 46, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f15", 47, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f16", 48, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f17", 49, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f18", 50, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f19", 51, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f20", 52, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f21", 53, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f22", 54, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f23", 55, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f24", 56, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f25", 57, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f26", 58, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f27", 59, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f28", 60, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f29", 61, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f30", 62, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "f31", 63, 1, NULL, 64, "ieee_double");
+  tdesc_create_reg (feature, "fpscr", 70, 1, "float", 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux");
+  tdesc_create_reg (feature, "orig_r3", 71, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "trap", 72, 1, NULL, 64, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.power.altivec");
+  field_type = tdesc_named_type (feature, "ieee_single");
+  type = init_vector_type (field_type, 4);
+  TYPE_NAME (type) = xstrdup ("v4f");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int32");
+  type = init_vector_type (field_type, 4);
+  TYPE_NAME (type) = xstrdup ("v4i32");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int16");
+  type = init_vector_type (field_type, 8);
+  TYPE_NAME (type) = xstrdup ("v8i16");
+  tdesc_record_type (feature, type);
+
+  field_type = tdesc_named_type (feature, "int8");
+  type = init_vector_type (field_type, 16);
+  TYPE_NAME (type) = xstrdup ("v16i8");
+  tdesc_record_type (feature, type);
+
+  type = init_composite_type (NULL, TYPE_CODE_UNION);
+  TYPE_NAME (type) = xstrdup ("vec128");
+  field_type = tdesc_named_type (feature, "uint128");
+  append_composite_type_field (type, xstrdup ("uint128"), field_type);
+  field_type = tdesc_named_type (feature, "v4f");
+  append_composite_type_field (type, xstrdup ("v4_float"), field_type);
+  field_type = tdesc_named_type (feature, "v4i32");
+  append_composite_type_field (type, xstrdup ("v4_int32"), field_type);
+  field_type = tdesc_named_type (feature, "v8i16");
+  append_composite_type_field (type, xstrdup ("v8_int16"), field_type);
+  field_type = tdesc_named_type (feature, "v16i8");
+  append_composite_type_field (type, xstrdup ("v16_int8"), field_type);
+  TYPE_VECTOR (type) = 1;
+  tdesc_record_type (feature, type);
+
+  tdesc_create_reg (feature, "vr0", 73, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr1", 74, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr2", 75, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr3", 76, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr4", 77, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr5", 78, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr6", 79, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr7", 80, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr8", 81, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr9", 82, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr10", 83, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr11", 84, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr12", 85, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr13", 86, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr14", 87, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr15", 88, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr16", 89, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr17", 90, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr18", 91, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr19", 92, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr20", 93, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr21", 94, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr22", 95, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr23", 96, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr24", 97, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr25", 98, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr26", 99, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr27", 100, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr28", 101, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr29", 102, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr30", 103, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vr31", 104, 1, NULL, 128, "vec128");
+  tdesc_create_reg (feature, "vscr", 105, 1, "vector", 32, "int");
+  tdesc_create_reg (feature, "vrsave", 106, 1, "vector", 32, "int");
+
+  tdesc_powerpc_cell64l = result;
+}
diff -urNp gdb-orig/gdb/features/rs6000/powerpc-cell64l.xml gdb-head/gdb/features/rs6000/powerpc-cell64l.xml
--- gdb-orig/gdb/features/rs6000/powerpc-cell64l.xml	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/features/rs6000/powerpc-cell64l.xml	2008-09-07 23:21:59.696167992 +0200
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- Cell/B.E. architecture.  Identical to the PowerPC 64-bit Linux UISA,
+     but adds support for the SPU as compatible architecture.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common64</architecture>
+  <compatible>spu</compatible>
+  <xi:include href="power64-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power64-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+</target>
diff -urNp gdb-orig/gdb/findvar.c gdb-head/gdb/findvar.c
--- gdb-orig/gdb/findvar.c	2008-09-05 13:34:13.000000000 +0200
+++ gdb-head/gdb/findvar.c	2008-09-07 23:21:57.556208682 +0200
@@ -308,13 +308,15 @@ value_of_register_lazy (struct frame_inf
 /* Given a pointer of type TYPE in target form in BUF, return the
    address it represents.  */
 CORE_ADDR
-unsigned_pointer_to_address (struct type *type, const gdb_byte *buf)
+unsigned_pointer_to_address (struct gdbarch *gdbarch,
+			     struct type *type, const gdb_byte *buf)
 {
   return extract_unsigned_integer (buf, TYPE_LENGTH (type));
 }
 
 CORE_ADDR
-signed_pointer_to_address (struct type *type, const gdb_byte *buf)
+signed_pointer_to_address (struct gdbarch *gdbarch,
+			   struct type *type, const gdb_byte *buf)
 {
   return extract_signed_integer (buf, TYPE_LENGTH (type));
 }
@@ -322,14 +324,15 @@ signed_pointer_to_address (struct type *
 /* Given an address, store it as a pointer of type TYPE in target
    format in BUF.  */
 void
-unsigned_address_to_pointer (struct type *type, gdb_byte *buf,
-			     CORE_ADDR addr)
+unsigned_address_to_pointer (struct gdbarch *gdbarch, struct type *type,
+			     gdb_byte *buf, CORE_ADDR addr)
 {
   store_unsigned_integer (buf, TYPE_LENGTH (type), addr);
 }
 
 void
-address_to_signed_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
+address_to_signed_pointer (struct gdbarch *gdbarch, struct type *type,
+			   gdb_byte *buf, CORE_ADDR addr)
 {
   store_signed_integer (buf, TYPE_LENGTH (type), addr);
 }
diff -urNp gdb-orig/gdb/frame.c gdb-head/gdb/frame.c
--- gdb-orig/gdb/frame.c	2008-08-26 19:38:08.000000000 +0200
+++ gdb-head/gdb/frame.c	2008-09-07 23:21:53.348148995 +0200
@@ -41,6 +41,7 @@
 #include "objfiles.h"
 #include "exceptions.h"
 #include "gdbthread.h"
+#include "arch-utils.h"
 
 static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
 
@@ -75,6 +76,13 @@ struct frame_info
   void *prologue_cache;
   const struct frame_unwind *unwind;
 
+  /* Cached copy of the previous frame's architecture.  */
+  struct
+  {
+    int p;
+    struct gdbarch *arch;
+  } prev_arch;
+
   /* Cached copy of the previous frame's resume address.  */
   struct {
     int p;
@@ -190,6 +198,9 @@ fprint_frame_type (struct ui_file *file,
     case SIGTRAMP_FRAME:
       fprintf_unfiltered (file, "SIGTRAMP_FRAME");
       return;
+    case ARCH_FRAME:
+      fprintf_unfiltered (file, "ARCH_FRAME");
+      return;
     default:
       fprintf_unfiltered (file, "<unknown type>");
       return;
@@ -251,6 +262,9 @@ get_frame_id (struct frame_info *fi)
     }
   if (!fi->this_id.p)
     {
+      struct cleanup *old_chain = save_current_gdbarch ();
+      current_gdbarch = get_frame_arch (fi);
+
       if (frame_debug)
 	fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
 			    fi->level);
@@ -266,6 +280,8 @@ get_frame_id (struct frame_info *fi)
 	  fprint_frame_id (gdb_stdlog, fi->this_id.value);
 	  fprintf_unfiltered (gdb_stdlog, " }\n");
 	}
+
+      do_cleanups (old_chain);
     }
   return fi->this_id.value;
 }
@@ -459,7 +475,7 @@ frame_pc_unwind (struct frame_info *this
   if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
-      if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+      if (gdbarch_unwind_pc_p (frame_arch_unwind (this_frame)))
 	{
 	  /* The right way.  The `pure' way.  The one true way.  This
 	     method depends solely on the register-unwind code to
@@ -477,7 +493,7 @@ frame_pc_unwind (struct frame_info *this
 	     frame.  This is all in stark contrast to the old
 	     FRAME_SAVED_PC which would try to directly handle all the
 	     different ways that a PC could be unwound.  */
-	  pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame);
+	  pc = gdbarch_unwind_pc (frame_arch_unwind (this_frame), this_frame);
 	}
       else
 	internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
@@ -647,19 +663,24 @@ get_frame_register (struct frame_info *f
 struct value *
 frame_unwind_register_value (struct frame_info *frame, int regnum)
 {
+  struct gdbarch *gdbarch;
   struct value *value;
+  struct cleanup *old_chain;
 
   gdb_assert (frame != NULL);
+  gdbarch = frame_arch_unwind (frame);
 
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "\
 { frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
 			  frame->level, regnum,
-			  user_reg_map_regnum_to_name
-			    (get_frame_arch (frame), regnum));
+			  user_reg_map_regnum_to_name (gdbarch, regnum));
     }
 
+  old_chain = save_current_gdbarch ();
+  current_gdbarch = gdbarch;
+
   /* Find the unwinder.  */
   if (frame->unwind == NULL)
     frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
@@ -692,7 +713,7 @@ frame_unwind_register_value (struct fram
 
 	      fprintf_unfiltered (gdb_stdlog, " bytes=");
 	      fprintf_unfiltered (gdb_stdlog, "[");
-	      for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+	      for (i = 0; i < register_size (gdbarch, regnum); i++)
 		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
 	      fprintf_unfiltered (gdb_stdlog, "]");
 	    }
@@ -701,6 +722,7 @@ frame_unwind_register_value (struct fram
       fprintf_unfiltered (gdb_stdlog, " }\n");
     }
 
+  do_cleanups (old_chain);
   return value;
 }
 
@@ -715,7 +737,7 @@ frame_unwind_register_signed (struct fra
 {
   gdb_byte buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  return extract_signed_integer (buf, register_size (get_frame_arch (frame),
+  return extract_signed_integer (buf, register_size (frame_arch_unwind (frame),
 						     regnum));
 }
 
@@ -730,7 +752,7 @@ frame_unwind_register_unsigned (struct f
 {
   gdb_byte buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
+  return extract_unsigned_integer (buf, register_size (frame_arch_unwind (frame),
 						       regnum));
 }
 
@@ -1046,6 +1068,8 @@ select_frame (struct frame_info *fi)
      source language of this frame, and switch to it if desired.  */
   if (fi)
     {
+      current_gdbarch = get_frame_arch (fi);
+
       /* We retrieve the frame's symtab by using the frame PC.  However
          we cannot use the frame PC as-is, because it usually points to
          the instruction following the "call", which is sometimes the
@@ -1702,9 +1726,17 @@ enum frame_type
 get_frame_type (struct frame_info *frame)
 {
   if (frame->unwind == NULL)
-    /* Initialize the frame's unwinder because that's what
-       provides the frame's type.  */
-    frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+    {
+      struct cleanup *old_chain = save_current_gdbarch ();
+      current_gdbarch = get_frame_arch (frame);
+
+      /* Initialize the frame's unwinder because that's what
+	 provides the frame's type.  */
+      frame->unwind = frame_unwind_find_by_frame (frame,
+						  &frame->prologue_cache);
+      do_cleanups (old_chain);
+    }
+
   return frame->unwind->type;
 }
 
@@ -1771,12 +1803,48 @@ safe_frame_unwind_memory (struct frame_i
   return !target_read_memory (addr, buf, len);
 }
 
-/* Architecture method.  */
+/* Architecture methods.  */
 
 struct gdbarch *
 get_frame_arch (struct frame_info *this_frame)
 {
-  return current_gdbarch;
+  return frame_arch_unwind (this_frame->next);
+}
+
+struct gdbarch *
+frame_arch_unwind (struct frame_info *next_frame)
+{
+  if (!next_frame->prev_arch.p)
+    {
+      struct gdbarch *arch;
+      struct cleanup *old_chain = save_current_gdbarch ();
+
+      if (next_frame->level >= 0)
+	current_gdbarch = get_frame_arch (next_frame);
+
+      if (next_frame->unwind == NULL)
+	next_frame->unwind
+	  = frame_unwind_find_by_frame (next_frame,
+					&next_frame->prologue_cache);
+
+      if (next_frame->unwind->prev_arch != NULL)
+	arch = next_frame->unwind->prev_arch (next_frame,
+					      &next_frame->prologue_cache);
+      else
+	arch = get_frame_arch (next_frame);
+
+      next_frame->prev_arch.arch = arch;
+      next_frame->prev_arch.p = 1;
+      if (frame_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "{ frame_arch_unwind (next_frame=%d) -> %s }\n",
+			    next_frame->level,
+			    gdbarch_bfd_arch_info (arch)->printable_name);
+
+      do_cleanups (old_chain);
+    }
+
+  return next_frame->prev_arch.arch;
 }
 
 /* Stack pointer methods.  */
diff -urNp gdb-orig/gdb/frame.h gdb-head/gdb/frame.h
--- gdb-orig/gdb/frame.h	2008-08-26 19:38:08.000000000 +0200
+++ gdb-head/gdb/frame.h	2008-09-07 23:21:52.590124201 +0200
@@ -180,6 +180,8 @@ enum frame_type
   /* In a signal handler, various OSs handle this in various ways.
      The main thing is that the frame may be far from normal.  */
   SIGTRAMP_FRAME,
+  /* Fake frame representing a cross-architecture call.  */
+  ARCH_FRAME,
   /* Sentinel or registers frame.  This frame obtains register values
      direct from the inferior's registers.  */
   SENTINEL_FRAME
@@ -518,6 +520,7 @@ extern int safe_frame_unwind_memory (str
 /* Return this frame's architecture.  */
 
 extern struct gdbarch *get_frame_arch (struct frame_info *this_frame);
+extern struct gdbarch *frame_arch_unwind (struct frame_info *next_frame);
 
 
 /* Values for the source flag to be used in print_frame_info_base().  */
diff -urNp gdb-orig/gdb/frame-unwind.c gdb-head/gdb/frame-unwind.c
--- gdb-orig/gdb/frame-unwind.c	2008-05-11 23:41:47.000000000 +0200
+++ gdb-head/gdb/frame-unwind.c	2008-09-07 23:21:52.595123483 +0200
@@ -126,7 +126,7 @@ default_frame_sniffer (const struct fram
 struct value *
 frame_unwind_got_optimized (struct frame_info *frame, int regnum)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -149,7 +149,7 @@ frame_unwind_got_register (struct frame_
 struct value *
 frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
 
   return value_at_lazy (register_type (gdbarch, regnum), addr);
 }
@@ -161,7 +161,7 @@ struct value *
 frame_unwind_got_constant (struct frame_info *frame, int regnum,
 			   ULONGEST val)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -173,7 +173,7 @@ frame_unwind_got_constant (struct frame_
 struct value *
 frame_unwind_got_bytes (struct frame_info *frame, int regnum, gdb_byte *buf)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -189,7 +189,7 @@ struct value *
 frame_unwind_got_address (struct frame_info *frame, int regnum,
 			  CORE_ADDR addr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
diff -urNp gdb-orig/gdb/frame-unwind.h gdb-head/gdb/frame-unwind.h
--- gdb-orig/gdb/frame-unwind.h	2008-05-11 23:41:47.000000000 +0200
+++ gdb-head/gdb/frame-unwind.h	2008-09-07 23:21:52.599122909 +0200
@@ -121,6 +121,13 @@ typedef struct value * (frame_prev_regis
 typedef void (frame_dealloc_cache_ftype) (struct frame_info *self,
 					  void *this_cache);
 
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+   use THIS frame, and implicitly the NEXT frame's register unwind
+   method, return PREV frame's architecture.  */
+
+typedef struct gdbarch *(frame_prev_arch_ftype) (struct frame_info *this_frame,
+						 void **this_prologue_cache);
+
 struct frame_unwind
 {
   /* The frame's type.  Should this instead be a collection of
@@ -133,6 +140,7 @@ struct frame_unwind
   const struct frame_data *unwind_data;
   frame_sniffer_ftype *sniffer;
   frame_dealloc_cache_ftype *dealloc_cache;
+  frame_prev_arch_ftype *prev_arch;
 };
 
 /* Register a frame unwinder, _prepending_ it to the front of the
diff -urNp gdb-orig/gdb/gcore.c gdb-head/gdb/gcore.c
--- gdb-orig/gdb/gcore.c	2008-09-05 13:33:41.000000000 +0200
+++ gdb-head/gdb/gcore.c	2008-09-07 23:21:58.270239934 +0200
@@ -35,7 +35,7 @@
    generate-core-file for programs with large resident data.  */
 #define MAX_COPY_BYTES (1024 * 1024)
 
-static char *default_gcore_target (void);
+static const char *default_gcore_target (void);
 static enum bfd_architecture default_gcore_arch (void);
 static unsigned long default_gcore_mach (void);
 static int gcore_memory_sections (bfd *);
@@ -125,7 +125,7 @@ default_gcore_mach (void)
   return 0;
 #else
 
-  const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (current_gdbarch);
+  const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch);
 
   if (bfdarch != NULL)
     return bfdarch->mach;
@@ -139,8 +139,7 @@ default_gcore_mach (void)
 static enum bfd_architecture
 default_gcore_arch (void)
 {
-  const struct bfd_arch_info * bfdarch = gdbarch_bfd_arch_info
-					 (current_gdbarch);
+  const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch);
 
   if (bfdarch != NULL)
     return bfdarch->arch;
@@ -150,10 +149,15 @@ default_gcore_arch (void)
   return bfd_get_arch (exec_bfd);
 }
 
-static char *
+static const char *
 default_gcore_target (void)
 {
-  /* FIXME: This may only work for ELF targets.  */
+  /* The gdbarch may define a target to use for core files.  */
+  if (gdbarch_gcore_bfd_target_p (target_gdbarch))
+    return gdbarch_gcore_bfd_target (target_gdbarch);
+
+  /* Otherwise, try to fall back to the exec_bfd target.  This will probably
+     not work for non-ELF targets.  */
   if (exec_bfd == NULL)
     return NULL;
   else
diff -urNp gdb-orig/gdb/gdbarch.c gdb-head/gdb/gdbarch.c
--- gdb-orig/gdb/gdbarch.c	2008-09-05 14:03:54.000000000 +0200
+++ gdb-head/gdb/gdbarch.c	2008-09-07 23:21:58.283238068 +0200
@@ -226,6 +226,7 @@ struct gdbarch
   gdbarch_regset_from_core_section_ftype *regset_from_core_section;
   struct core_regset_section * core_regset_sections;
   gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
+  const char * gcore_bfd_target;
   int vtable_function_descriptors;
   int vbit_in_delta;
   gdbarch_skip_permanent_breakpoint_ftype *skip_permanent_breakpoint;
@@ -312,8 +313,8 @@ struct gdbarch startup_gdbarch =
   0,  /* register_to_value */
   0,  /* value_to_register */
   0,  /* value_from_register */
-  0,  /* pointer_to_address */
-  0,  /* address_to_pointer */
+  unsigned_pointer_to_address,  /* pointer_to_address */
+  unsigned_address_to_pointer,  /* address_to_pointer */
   0,  /* integer_to_address */
   0,  /* return_value */
   0,  /* skip_prologue */
@@ -358,6 +359,7 @@ struct gdbarch startup_gdbarch =
   0,  /* regset_from_core_section */
   0,  /* core_regset_sections */
   0,  /* core_xfer_shared_libraries */
+  0,  /* gcore_bfd_target */
   0,  /* vtable_function_descriptors */
   0,  /* vbit_in_delta */
   0,  /* skip_permanent_breakpoint */
@@ -610,6 +612,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of fetch_pointer_argument, has predicate */
   /* Skip verify of regset_from_core_section, has predicate */
   /* Skip verify of core_xfer_shared_libraries, has predicate */
+  /* Skip verify of gcore_bfd_target, has predicate */
   /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
   /* Skip verify of vbit_in_delta, invalid_p == 0 */
   /* Skip verify of skip_permanent_breakpoint, has predicate */
@@ -830,6 +833,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: frame_red_zone_size = %s\n",
                       plongest (gdbarch->frame_red_zone_size));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_gcore_bfd_target_p() = %d\n",
+                      gdbarch_gcore_bfd_target_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gcore_bfd_target = %s\n",
+                      gdbarch->gcore_bfd_target);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_get_longjmp_target_p() = %d\n",
                       gdbarch_get_longjmp_target_p (gdbarch));
   fprintf_unfiltered (file,
@@ -2056,7 +2065,7 @@ gdbarch_pointer_to_address (struct gdbar
   gdb_assert (gdbarch->pointer_to_address != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_pointer_to_address called\n");
-  return gdbarch->pointer_to_address (type, buf);
+  return gdbarch->pointer_to_address (gdbarch, type, buf);
 }
 
 void
@@ -2073,7 +2082,7 @@ gdbarch_address_to_pointer (struct gdbar
   gdb_assert (gdbarch->address_to_pointer != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_address_to_pointer called\n");
-  gdbarch->address_to_pointer (type, buf, addr);
+  gdbarch->address_to_pointer (gdbarch, type, buf, addr);
 }
 
 void
@@ -2949,6 +2958,31 @@ set_gdbarch_core_xfer_shared_libraries (
 }
 
 int
+gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->gcore_bfd_target != 0;
+}
+
+const char *
+gdbarch_gcore_bfd_target (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  /* Check variable changed from pre-default.  */
+  gdb_assert (gdbarch->gcore_bfd_target != 0);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_gcore_bfd_target called\n");
+  return gdbarch->gcore_bfd_target;
+}
+
+void
+set_gdbarch_gcore_bfd_target (struct gdbarch *gdbarch,
+                              const char * gcore_bfd_target)
+{
+  gdbarch->gcore_bfd_target = gcore_bfd_target;
+}
+
+int
 gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
@@ -3368,10 +3402,15 @@ gdbarch_data (struct gdbarch *gdbarch, s
 	   (as all fields are valid), but be careful to also detect
 	   recursive references.  */
 	{
+	  struct cleanup *old_chain = save_current_gdbarch ();
+	  current_gdbarch = gdbarch;
+
 	  gdb_assert (data->init_p);
 	  data->init_p = 0;
 	  gdbarch->data[data->index] = data->post_init (gdbarch);
 	  data->init_p = 1;
+
+	  do_cleanups (old_chain);
 	}
       else
 	/* The architecture initialization hasn't completed - punt -
diff -urNp gdb-orig/gdb/gdbarch.h gdb-head/gdb/gdbarch.h
--- gdb-orig/gdb/gdbarch.h	2008-09-05 13:42:04.000000000 +0200
+++ gdb-head/gdb/gdbarch.h	2008-09-07 23:21:58.292236777 +0200
@@ -348,11 +348,11 @@ typedef struct value * (gdbarch_value_fr
 extern struct value * gdbarch_value_from_register (struct gdbarch *gdbarch, struct type *type, int regnum, struct frame_info *frame);
 extern void set_gdbarch_value_from_register (struct gdbarch *gdbarch, gdbarch_value_from_register_ftype *value_from_register);
 
-typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct type *type, const gdb_byte *buf);
+typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
 
-typedef void (gdbarch_address_to_pointer_ftype) (struct type *type, gdb_byte *buf, CORE_ADDR addr);
+typedef void (gdbarch_address_to_pointer_ftype) (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr);
 extern void gdbarch_address_to_pointer (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr);
 extern void set_gdbarch_address_to_pointer (struct gdbarch *gdbarch, gdbarch_address_to_pointer_ftype *address_to_pointer);
 
@@ -655,6 +655,13 @@ typedef LONGEST (gdbarch_core_xfer_share
 extern LONGEST gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len);
 extern void set_gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries);
 
+/* BFD target to use when generating a core file. */
+
+extern int gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch);
+
+extern const char * gdbarch_gcore_bfd_target (struct gdbarch *gdbarch);
+extern void set_gdbarch_gcore_bfd_target (struct gdbarch *gdbarch, const char * gcore_bfd_target);
+
 /* If the elements of C++ vtables are in-place function descriptors rather
    than normal function pointers (which may point to code or a descriptor),
    set this to one. */
diff -urNp gdb-orig/gdb/gdbarch.sh gdb-head/gdb/gdbarch.sh
--- gdb-orig/gdb/gdbarch.sh	2008-09-05 14:03:29.000000000 +0200
+++ gdb-head/gdb/gdbarch.sh	2008-09-07 23:21:58.301235485 +0200
@@ -466,8 +466,8 @@ f:void:value_to_register:struct frame_in
 # (but not the value contents) filled in.
 f:struct value *:value_from_register:struct type *type, int regnum, struct frame_info *frame:type, regnum, frame::default_value_from_register::0
 #
-f:CORE_ADDR:pointer_to_address:struct type *type, const gdb_byte *buf:type, buf::unsigned_pointer_to_address::0
-f:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
+m:CORE_ADDR:pointer_to_address:struct type *type, const gdb_byte *buf:type, buf::unsigned_pointer_to_address::0
+m:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
 M:CORE_ADDR:integer_to_address:struct type *type, const gdb_byte *buf:type, buf
 
 # Return the return-value convention that will be used by FUNCTYPE
@@ -608,6 +608,9 @@ v:struct core_regset_section *:core_regs
 # core file into buffer READBUF with length LEN.
 M:LONGEST:core_xfer_shared_libraries:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len
 
+# BFD target to use when generating a core file.
+V:const char *:gcore_bfd_target:::0:0:::gdbarch->gcore_bfd_target
+
 # If the elements of C++ vtables are in-place function descriptors rather
 # than normal function pointers (which may point to code or a descriptor),
 # set this to one.
@@ -1725,10 +1728,15 @@ gdbarch_data (struct gdbarch *gdbarch, s
 	   (as all fields are valid), but be careful to also detect
 	   recursive references.  */
 	{
+	  struct cleanup *old_chain = save_current_gdbarch ();
+	  current_gdbarch = gdbarch;
+
 	  gdb_assert (data->init_p);
 	  data->init_p = 0;
 	  gdbarch->data[data->index] = data->post_init (gdbarch);
 	  data->init_p = 1;
+
+	  do_cleanups (old_chain);
 	}
       else
 	/* The architecture initialization hasn't completed - punt -
diff -urNp gdb-orig/gdb/gdbserver/configure.srv gdb-head/gdb/gdbserver/configure.srv
--- gdb-orig/gdb/gdbserver/configure.srv	2008-09-05 13:33:42.000000000 +0200
+++ gdb-head/gdb/gdbserver/configure.srv	2008-09-07 23:21:59.701167274 +0200
@@ -102,14 +102,17 @@ case "${target}" in
 			;;
   powerpc*-*-linux*)	srv_regobj="powerpc-32l.o"
 			srv_regobj="${srv_regobj} powerpc-altivec32l.o"
+			srv_regobj="${srv_regobj} powerpc-cell32l.o"
 			srv_regobj="${srv_regobj} powerpc-vsx32l.o"
 			srv_regobj="${srv_regobj} powerpc-e500l.o"
 			srv_regobj="${srv_regobj} powerpc-64l.o"
 			srv_regobj="${srv_regobj} powerpc-altivec64l.o"
+			srv_regobj="${srv_regobj} powerpc-cell64l.o"
 			srv_regobj="${srv_regobj} powerpc-vsx64l.o"
 			srv_tgtobj="linux-low.o linux-ppc-low.o"
 			srv_xmlfiles="rs6000/powerpc-32l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml"
+			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-cell32l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx32l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-altivec.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-vsx.xml"
@@ -120,6 +123,7 @@ case "${target}" in
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec64l.xml"
+			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-cell64l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx64l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power64-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power64-linux.xml"
diff -urNp gdb-orig/gdb/gdbserver/linux-low.c gdb-head/gdb/gdbserver/linux-low.c
--- gdb-orig/gdb/gdbserver/linux-low.c	2008-08-14 22:08:49.000000000 +0200
+++ gdb-head/gdb/gdbserver/linux-low.c	2008-09-07 23:21:54.061179390 +0200
@@ -33,6 +33,14 @@
 #include <errno.h>
 #include <sys/syscall.h>
 #include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <dirent.h>
+
+#ifndef SPUFS_MAGIC
+#define SPUFS_MAGIC 0x23c9b64e
+#endif
 
 #ifndef PTRACE_GETSIGINFO
 # define PTRACE_GETSIGINFO 0x4202
@@ -2037,6 +2045,102 @@ linux_read_offsets (CORE_ADDR *text_p, C
 }
 #endif
 
+
+/* Enumerate spufs IDs for process PID.  */
+static int
+spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
+{
+  int pos = 0;
+  int written = 0;
+  char path[128];
+  DIR *dir;
+  struct dirent *entry;
+
+  sprintf (path, "/proc/%ld/fd", pid);
+  dir = opendir (path);
+  if (!dir)
+    return -1;
+
+  rewinddir (dir);
+  while ((entry = readdir (dir)) != NULL)
+    {
+      struct stat st;
+      struct statfs stfs;
+      int fd;
+
+      fd = atoi (entry->d_name);
+      if (!fd)
+        continue;
+
+      sprintf (path, "/proc/%ld/fd/%d", pid, fd);
+      if (stat (path, &st) != 0)
+        continue;
+      if (!S_ISDIR (st.st_mode))
+        continue;
+
+      if (statfs (path, &stfs) != 0)
+        continue;
+      if (stfs.f_type != SPUFS_MAGIC)
+        continue;
+
+      if (pos >= offset && pos + 4 <= offset + len)
+        {
+          *(unsigned int *)(buf + pos - offset) = fd;
+          written += 4;
+        }
+      pos += 4;
+    }
+
+  closedir (dir);
+  return written;
+}
+
+/* Implements the to_xfer_partial interface for the TARGET_OBJECT_SPU
+   object type, using the /proc file system */
+static int
+linux_spu_qxfer_partial (const char *annex, unsigned char *readbuf,
+                         unsigned const char *writebuf,
+                         CORE_ADDR offset, int len)
+{
+  char buf[128];
+  int fd = 0;
+  int ret = 0;
+
+  if (!writebuf && !readbuf)
+    return -1;
+
+  if (!*annex)
+    {
+      if (!readbuf)
+        return -1;
+      else
+        return spu_enumerate_spu_ids (inferior_pid, readbuf, offset, len);
+    }
+
+  sprintf (buf, "/proc/%ld/fd/%s", inferior_pid, annex);
+  if (debug_threads)
+    printf ("access [%s] |offset [%lld] | len [%d]\n", buf, offset, len);
+
+  fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
+  if (fd <= 0)
+    return -1;
+
+  if (offset != 0
+      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+    {
+      close (fd);
+      return 0;
+    }
+
+  if (writebuf)
+    ret = write (fd, writebuf, (size_t) len);
+  else
+    ret = read (fd, readbuf, (size_t) len);
+
+  close (fd);
+  return ret;
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
@@ -2067,7 +2171,7 @@ static struct target_ops linux_target_op
 #else
   NULL,
 #endif
-  NULL,
+  linux_spu_qxfer_partial,
   hostio_last_error_from_errno,
 };
 
diff -urNp gdb-orig/gdb/gdbserver/linux-ppc-low.c gdb-head/gdb/gdbserver/linux-ppc-low.c
--- gdb-orig/gdb/gdbserver/linux-ppc-low.c	2008-08-21 21:44:33.000000000 +0200
+++ gdb-head/gdb/gdbserver/linux-ppc-low.c	2008-09-07 23:22:01.238212133 +0200
@@ -28,6 +28,7 @@
 #define PPC_FEATURE_HAS_VSX		0x00000080
 #define PPC_FEATURE_HAS_ALTIVEC         0x10000000
 #define PPC_FEATURE_HAS_SPE             0x00800000
+#define PPC_FEATURE_CELL		0x00010000
 
 static unsigned long ppc_hwcap;
 
@@ -36,6 +37,8 @@ static unsigned long ppc_hwcap;
 void init_registers_powerpc_32l (void);
 /* Defined in auto-generated file powerpc-altivec32l.c.  */
 void init_registers_powerpc_altivec32l (void);
+/* Defined in auto-generated file powerpc-cell32l.c.  */
+void init_registers_powerpc_cell32l (void);
 /* Defined in auto-generated file powerpc-vsx32l.c.  */
 void init_registers_powerpc_vsx32l (void);
 /* Defined in auto-generated file powerpc-e500l.c.  */
@@ -44,6 +47,8 @@ void init_registers_powerpc_e500l (void)
 void init_registers_powerpc_64l (void);
 /* Defined in auto-generated file powerpc-altivec64l.c.  */
 void init_registers_powerpc_altivec64l (void);
+/* Defined in auto-generated file powerpc-cell64l.c.  */
+void init_registers_powerpc_cell64l (void);
 /* Defined in auto-generated file powerpc-vsx64l.c.  */
 void init_registers_powerpc_vsx64l (void);
 
@@ -173,10 +178,72 @@ ppc_supply_ptrace_register (int regno, c
     supply_register (regno, buf);
 }
 
+
+#define INSTR_SC        0x44000002
+#define NR_spu_run      0x0116
+
+/* If the PPU thread is currently stopped on a spu_run system call,
+   return to FD and ADDR the file handle and NPC parameter address
+   used with the system call.  Return non-zero if successful.  */
+static int
+parse_spufs_run (int *fd, CORE_ADDR *addr)
+{
+  CORE_ADDR curr_pc;
+  int curr_insn;
+  int curr_r0;
+
+  if (register_size (0) == 4)
+    {
+      unsigned int pc, r0, r3, r4;
+      collect_register_by_name ("pc", &pc);
+      collect_register_by_name ("r0", &r0);
+      collect_register_by_name ("orig_r3", &r3);
+      collect_register_by_name ("r4", &r4);
+      curr_pc = (CORE_ADDR) pc;
+      curr_r0 = (int) r0;
+      *fd = (int) r3;
+      *addr = (CORE_ADDR) r4;
+    }
+  else
+    {
+      unsigned long pc, r0, r3, r4;
+      collect_register_by_name ("pc", &pc);
+      collect_register_by_name ("r0", &r0);
+      collect_register_by_name ("orig_r3", &r3);
+      collect_register_by_name ("r4", &r4);
+      curr_pc = (CORE_ADDR) pc;
+      curr_r0 = (int) r0;
+      *fd = (int) r3;
+      *addr = (CORE_ADDR) r4;
+    }
+
+  /* Fetch instruction preceding current NIP.  */
+  if ((*the_target->read_memory) (curr_pc - 4,
+				  (unsigned char *) &curr_insn, 4) != 0)
+    return 0;
+  /* It should be a "sc" instruction.  */
+  if (curr_insn != INSTR_SC)
+    return 0;
+  /* System call number should be NR_spu_run.  */
+  if (curr_r0 != NR_spu_run)
+    return 0;
+
+  return 1;
+}
+
 static CORE_ADDR
 ppc_get_pc (void)
 {
-  if (register_size (0) == 4)
+  CORE_ADDR addr;
+  int fd;
+
+  if (parse_spufs_run (&fd, &addr))
+    {
+      unsigned int pc;
+      (*the_target->read_memory) (addr, (unsigned char *) &pc, 4);
+      return ((CORE_ADDR)1 << 63) | ((CORE_ADDR)fd << 32) | (CORE_ADDR) (pc - 4);
+    }
+  else if (register_size (0) == 4)
     {
       unsigned int pc;
       collect_register_by_name ("pc", &pc);
@@ -193,7 +260,15 @@ ppc_get_pc (void)
 static void
 ppc_set_pc (CORE_ADDR pc)
 {
-  if (register_size (0) == 4)
+  CORE_ADDR addr;
+  int fd;
+
+  if (parse_spufs_run (&fd, &addr))
+    {
+      unsigned int newpc = pc;
+      (*the_target->write_memory) (addr, (unsigned char *) &newpc, 4);
+    }
+  else if (register_size (0) == 4)
     {
       unsigned int newpc = pc;
       supply_register_by_name ("pc", &newpc);
@@ -259,7 +334,9 @@ ppc_arch_setup (void)
   if (msr < 0)
     {
       ppc_get_hwcap (&ppc_hwcap);
-      if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
+      if (ppc_hwcap & PPC_FEATURE_CELL)
+	init_registers_powerpc_cell64l ();
+      else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
 	init_registers_powerpc_vsx64l ();
       else if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)
 	init_registers_powerpc_altivec64l ();
@@ -271,7 +348,9 @@ ppc_arch_setup (void)
   init_registers_powerpc_32l ();
 
   ppc_get_hwcap (&ppc_hwcap);
-  if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
+  if (ppc_hwcap & PPC_FEATURE_CELL)
+    init_registers_powerpc_cell32l ();
+  else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
     init_registers_powerpc_vsx32l ();
   else if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)
     init_registers_powerpc_altivec32l ();
@@ -300,11 +379,24 @@ ppc_breakpoint_at (CORE_ADDR where)
 {
   unsigned int insn;
 
-  (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
-  if (insn == ppc_breakpoint)
-    return 1;
-  /* If necessary, recognize more trap instructions here.  GDB only uses the
-     one.  */
+  if (where & ((CORE_ADDR)1 << 63))
+    {
+      char mem_annex[32];
+      sprintf (mem_annex, "%d/mem", (int)((where >> 32) & 0x7fffffff));
+      (*the_target->qxfer_spu) (mem_annex, (unsigned char *) &insn,
+				NULL, where & 0xffffffff, 4);
+      if (insn == 0x3fff)
+	return 1;
+    }
+  else
+    {
+      (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
+      if (insn == ppc_breakpoint)
+	return 1;
+      /* If necessary, recognize more trap instructions here.  GDB only uses
+	 the one.  */
+    }
+
   return 0;
 }
 
diff -urNp gdb-orig/gdb/gdbserver/Makefile.in gdb-head/gdb/gdbserver/Makefile.in
--- gdb-orig/gdb/gdbserver/Makefile.in	2008-08-26 14:42:20.000000000 +0200
+++ gdb-head/gdb/gdbserver/Makefile.in	2008-09-07 23:21:59.710165982 +0200
@@ -224,8 +224,9 @@ clean:
 	rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c
 	rm -f arm-with-iwmmxt.c mips-linux.c mips64-linux.c
 	rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c
-	rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c
-	rm -f powerpc-vsx64l.c xml-builtin.c stamp-xml
+	rm -f powerpc-altivec32l.c powerpc-cell32l.c powerpc-vsx32l.c
+	rm -f powerpc-altivec64l.c powerpc-cell64l.c powerpc-vsx64l.c
+	rm -f xml-builtin.c stamp-xml
 
 maintainer-clean realclean distclean: clean
 	rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@@ -369,6 +370,9 @@ powerpc-32l.c : $(srcdir)/../regformats/
 powerpc-altivec32l.o : powerpc-altivec32l.c $(regdef_h)
 powerpc-altivec32l.c : $(srcdir)/../regformats/rs6000/powerpc-altivec32l.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-altivec32l.dat powerpc-altivec32l.c
+powerpc-cell32l.o : powerpc-cell32l.c $(regdef_h)
+powerpc-cell32l.c : $(srcdir)/../regformats/rs6000/powerpc-cell32l.dat $(regdat_sh)
+	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-cell32l.dat powerpc-cell32l.c
 powerpc-vsx32l.o : powerpc-vsx32l.c $(regdef_h)
 powerpc-vsx32l.c : $(srcdir)/../regformats/rs6000/powerpc-vsx32l.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-vsx32l.dat powerpc-vsx32l.c
@@ -381,6 +385,9 @@ powerpc-64l.c : $(srcdir)/../regformats/
 powerpc-altivec64l.o : powerpc-altivec64l.c $(regdef_h)
 powerpc-altivec64l.c : $(srcdir)/../regformats/rs6000/powerpc-altivec64l.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-altivec64l.dat powerpc-altivec64l.c
+powerpc-cell64l.o : powerpc-cell64l.c $(regdef_h)
+powerpc-cell64l.c : $(srcdir)/../regformats/rs6000/powerpc-cell64l.dat $(regdat_sh)
+	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-cell64l.dat powerpc-cell64l.c
 powerpc-vsx64l.o : powerpc-vsx64l.c $(regdef_h)
 powerpc-vsx64l.c : $(srcdir)/../regformats/rs6000/powerpc-vsx64l.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-vsx64l.dat powerpc-vsx64l.c
diff -urNp gdb-orig/gdb/i386-nat.c gdb-head/gdb/i386-nat.c
--- gdb-orig/gdb/i386-nat.c	2008-03-01 05:39:36.000000000 +0100
+++ gdb-head/gdb/i386-nat.c	2008-09-07 23:21:55.476110027 +0200
@@ -640,14 +640,14 @@ i386_insert_hw_breakpoint (struct bp_tar
 }
 
 /* Remove a hardware-assisted breakpoint at BP_TGT->placed_address.
-   Return 0 on success, -1 on failure.  */
+   Return 0 on success, EBUSY on failure.  */
 
 int
 i386_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
 {
   unsigned len_rw = i386_length_and_rw_bits (1, hw_execute);
   CORE_ADDR addr = bp_tgt->placed_address;
-  int retval = i386_remove_aligned_watchpoint (addr, len_rw);
+  int retval = i386_remove_aligned_watchpoint (addr, len_rw) ? EBUSY : 0;
 
   if (maint_show_dr)
     i386_show_dr ("remove_hwbp", addr, 1, hw_execute);
diff -urNp gdb-orig/gdb/inferior.h gdb-head/gdb/inferior.h
--- gdb-orig/gdb/inferior.h	2008-07-12 22:00:18.000000000 +0200
+++ gdb-head/gdb/inferior.h	2008-09-07 23:21:57.590203802 +0200
@@ -156,13 +156,17 @@ extern CORE_ADDR read_pc (void);
 
 extern void write_pc (CORE_ADDR);
 
-extern CORE_ADDR unsigned_pointer_to_address (struct type *type,
+extern CORE_ADDR unsigned_pointer_to_address (struct gdbarch *gdbarch,
+					      struct type *type,
 					      const gdb_byte *buf);
-extern void unsigned_address_to_pointer (struct type *type, gdb_byte *buf,
+extern void unsigned_address_to_pointer (struct gdbarch *gdbarch,
+					 struct type *type, gdb_byte *buf,
 					 CORE_ADDR addr);
-extern CORE_ADDR signed_pointer_to_address (struct type *type,
+extern CORE_ADDR signed_pointer_to_address (struct gdbarch *gdbarch,
+					    struct type *type,
 					    const gdb_byte *buf);
-extern void address_to_signed_pointer (struct type *type, gdb_byte *buf,
+extern void address_to_signed_pointer (struct gdbarch *gdbarch,
+				       struct type *type, gdb_byte *buf,
 				       CORE_ADDR addr);
 
 extern void wait_for_inferior (int treat_exec_as_sigtrap);
diff -urNp gdb-orig/gdb/iq2000-tdep.c gdb-head/gdb/iq2000-tdep.c
--- gdb-orig/gdb/iq2000-tdep.c	2008-08-26 14:42:19.000000000 +0200
+++ gdb-head/gdb/iq2000-tdep.c	2008-09-07 23:21:57.595203084 +0200
@@ -86,7 +86,8 @@ insn_addr_from_ptr (CORE_ADDR ptr)	/* ta
    Convert a target pointer to an address in host (CORE_ADDR) format. */
 
 static CORE_ADDR
-iq2000_pointer_to_address (struct type * type, const gdb_byte * buf)
+iq2000_pointer_to_address (struct gdbarch *gdbarch,
+			   struct type * type, const gdb_byte * buf)
 {
   enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
   CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
@@ -103,7 +104,8 @@ iq2000_pointer_to_address (struct type *
    Convert a host-format address (CORE_ADDR) into a target pointer.  */
 
 static void
-iq2000_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
+iq2000_address_to_pointer (struct gdbarch *gdbarch,
+			   struct type *type, gdb_byte *buf, CORE_ADDR addr)
 {
   enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
 
diff -urNp gdb-orig/gdb/linux-nat.c gdb-head/gdb/linux-nat.c
--- gdb-orig/gdb/linux-nat.c	2008-08-21 21:44:32.000000000 +0200
+++ gdb-head/gdb/linux-nat.c	2008-09-07 23:21:54.075177381 +0200
@@ -49,6 +49,12 @@
 #include "inf-loop.h"
 #include "event-loop.h"
 #include "event-top.h"
+#include <sys/vfs.h>		/* for struct statfs */
+#include <dirent.h>		/* for DIR etc. */
+
+#ifndef SPUFS_MAGIC
+#define SPUFS_MAGIC 0x23c9b64e
+#endif
 
 #ifdef HAVE_PERSONALITY
 # include <sys/personality.h>
@@ -3330,8 +3336,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;
@@ -3452,6 +3458,119 @@ linux_nat_do_registers (bfd *obfd, ptid_
 					note_data, note_size);
 }
 
+/* Enumerate spufs IDs for process PID.  */
+
+static void
+iterate_over_spus (int pid, void (*callback) (void *, int), void *data)
+{
+  char path[128];
+  DIR *dir;
+  struct dirent *entry;
+
+  xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
+  dir = opendir (path);
+  if (!dir)
+    return;
+
+  rewinddir (dir);
+  while ((entry = readdir (dir)) != NULL)
+    {
+      struct stat st;
+      struct statfs stfs;
+      int fd;
+
+      fd = atoi (entry->d_name);
+      if (!fd)
+	continue;
+
+      xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
+      if (stat (path, &st) != 0)
+	continue;
+      if (!S_ISDIR (st.st_mode))
+	continue;
+
+      if (statfs (path, &stfs) != 0)
+	continue;
+      if (stfs.f_type != SPUFS_MAGIC)
+	continue;
+
+      callback (data, fd);
+    }
+
+  closedir (dir);
+}
+
+/* Generate corefile notes for SPU contexts.  */
+
+struct linux_spu_corefile_data
+{
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+};
+
+static void
+linux_spu_corefile_callback (void *data, int fd)
+{
+  struct linux_spu_corefile_data *args = data;
+  int i;
+
+  static const char *spu_files[] =
+    {
+      "object-id",
+      "mem",
+      "regs",
+      "fpcr",
+      "lslr",
+      "decr",
+      "decr_status",
+      "signal1",
+      "signal1_type",
+      "signal2",
+      "signal2_type",
+      "event_mask",
+      "event_status",
+      "mbox_info",
+      "ibox_info",
+      "wbox_info",
+      "dma_info",
+      "proxydma_info",
+   };
+
+  for (i = 0; i < sizeof (spu_files) / sizeof (spu_files[0]); i++)
+    {
+      char annex[32], note_name[32];
+      gdb_byte *spu_data;
+      LONGEST spu_len;
+
+      xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[i]);
+      spu_len = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
+				   annex, &spu_data);
+      if (spu_len > 0)
+	{
+	  xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
+	  args->note_data = elfcore_write_note (args->obfd, args->note_data,
+						args->note_size, note_name,
+						NT_SPU, spu_data, spu_len);
+	  xfree (spu_data);
+	}
+    }
+}
+
+static char *
+linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
+{
+  struct linux_spu_corefile_data args;
+  args.obfd = obfd;
+  args.note_data = note_data;
+  args.note_size = note_size;
+
+  iterate_over_spus (PIDGET (inferior_ptid),
+		     linux_spu_corefile_callback, &args);
+
+  return args.note_data;
+}
+
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
    section for a corefile, and returns it in a malloc buffer.  */
 
@@ -3520,6 +3639,8 @@ linux_nat_make_corefile_notes (bfd *obfd
       xfree (auxv);
     }
 
+  note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
+
   make_cleanup (xfree, note_data);
   return note_data;
 }
@@ -3846,6 +3967,99 @@ linux_proc_xfer_partial (struct target_o
   return ret;
 }
 
+
+/* Enumerate spufs IDs for process PID.  */
+static LONGEST
+spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, LONGEST len)
+{
+  LONGEST pos = 0;
+  LONGEST written = 0;
+  char path[128];
+  DIR *dir;
+  struct dirent *entry;
+
+  xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
+  dir = opendir (path);
+  if (!dir)
+    return -1;
+
+  rewinddir (dir);
+  while ((entry = readdir (dir)) != NULL)
+    {
+      struct stat st;
+      struct statfs stfs;
+      int fd;
+
+      fd = atoi (entry->d_name);
+      if (!fd)
+	continue;
+
+      xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
+      if (stat (path, &st) != 0)
+	continue;
+      if (!S_ISDIR (st.st_mode))
+	continue;
+
+      if (statfs (path, &stfs) != 0)
+	continue;
+      if (stfs.f_type != SPUFS_MAGIC)
+	continue;
+
+      if (pos >= offset && pos + 4 <= offset + len)
+	{
+	  store_unsigned_integer (buf + pos - offset, 4, fd);
+	  written += 4;
+	}
+      pos += 4;
+    }
+
+  closedir (dir);
+  return written;
+}
+
+/* Implement the to_xfer_partial interface for the TARGET_OBJECT_SPU
+   object type, using the /proc file system.  */
+static LONGEST
+linux_proc_xfer_spu (struct target_ops *ops, enum target_object object,
+		     const char *annex, gdb_byte *readbuf,
+		     const gdb_byte *writebuf,
+		     ULONGEST offset, LONGEST len)
+{
+  char buf[128];
+  int fd = 0;
+  int ret = -1;
+  int pid = PIDGET (inferior_ptid);
+
+  if (!annex)
+    {
+      if (!readbuf)
+	return -1;
+      else
+	return spu_enumerate_spu_ids (pid, readbuf, offset, len);
+  }
+
+  xsnprintf (buf, sizeof buf, "/proc/%d/fd/%s", pid, annex);
+  fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
+  if (fd <= 0)
+    return -1;
+
+  if (offset != 0
+      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+    {
+      close (fd);
+      return 0;
+    }
+
+  if (writebuf)
+    ret = write (fd, writebuf, (size_t) len);
+  else if (readbuf)
+    ret = read (fd, readbuf, (size_t) len);
+
+  close (fd);
+  return ret;
+}
+
+
 /* Parse LINE as a signal set and add its set bits to SIGS.  */
 
 static void
@@ -3938,6 +4152,10 @@ linux_xfer_partial (struct target_ops *o
     return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
 			     offset, len);
 
+  if (object == TARGET_OBJECT_SPU)
+    return linux_proc_xfer_spu (ops, object, annex, readbuf, writebuf,
+				offset, len);
+
   xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
 				  offset, len);
   if (xfer != 0)
diff -urNp gdb-orig/gdb/m32c-tdep.c gdb-head/gdb/m32c-tdep.c
--- gdb-orig/gdb/m32c-tdep.c	2008-07-12 22:00:18.000000000 +0200
+++ gdb-head/gdb/m32c-tdep.c	2008-09-07 23:21:57.604201793 +0200
@@ -2397,7 +2397,8 @@ m32c_skip_trampoline_code (struct frame_
    programmer!  :)  */
 
 static void
-m32c_m16c_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
+m32c_m16c_address_to_pointer (struct gdbarch *gdbarch,
+			      struct type *type, gdb_byte *buf, CORE_ADDR addr)
 {
   enum type_code target_code;
   gdb_assert (TYPE_CODE (type) == TYPE_CODE_PTR ||
@@ -2445,7 +2446,8 @@ m32c_m16c_address_to_pointer (struct typ
 
 
 static CORE_ADDR
-m32c_m16c_pointer_to_address (struct type *type, const gdb_byte *buf)
+m32c_m16c_pointer_to_address (struct gdbarch *gdbarch,
+			      struct type *type, const gdb_byte *buf)
 {
   CORE_ADDR ptr;
   enum type_code target_code;
diff -urNp gdb-orig/gdb/Makefile.in gdb-head/gdb/Makefile.in
--- gdb-orig/gdb/Makefile.in	2008-08-21 21:44:30.000000000 +0200
+++ gdb-head/gdb/Makefile.in	2008-09-07 23:22:00.496185900 +0200
@@ -498,7 +498,7 @@ ALL_TARGET_OBS = \
 	sh64-tdep.o sh-linux-tdep.o shnbsd-tdep.o sh-tdep.o \
 	sparc-linux-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o \
 	sparc-sol2-tdep.o sparc-tdep.o \
-	spu-tdep.o \
+	spu-tdep.o spu-multiarch.o solib-spu.o \
 	v850-tdep.o \
 	vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
 	xstormy16-tdep.o \
@@ -1331,7 +1331,7 @@ ALLDEPFILES = \
 	sparc64-tdep.c sparc64fbsd-nat.c sparc64fbsd-tdep.c \
 	sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
 	sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
-	spu-linux-nat.c spu-tdep.c \
+	spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
 	v850-tdep.c \
 	vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
 	win32-nat.c \
diff -urNp gdb-orig/gdb/objfiles.c gdb-head/gdb/objfiles.c
--- gdb-orig/gdb/objfiles.c	2008-09-05 13:34:13.000000000 +0200
+++ gdb-head/gdb/objfiles.c	2008-09-07 23:21:56.161143441 +0200
@@ -672,7 +672,7 @@ objfile_relocate (struct objfile *objfil
     }
 
   /* Relocate breakpoints as necessary, after things are relocated. */
-  breakpoint_re_set ();
+  breakpoint_relocate (objfile, delta);
 }
 
 /* Many places in gdb want to test just to see if we have any partial
diff -urNp gdb-orig/gdb/ppc-linux-nat.c gdb-head/gdb/ppc-linux-nat.c
--- gdb-orig/gdb/ppc-linux-nat.c	2008-08-21 21:44:32.000000000 +0200
+++ gdb-head/gdb/ppc-linux-nat.c	2008-09-07 23:21:59.716165121 +0200
@@ -56,6 +56,10 @@
 #define PT_TRAP 40
 #endif
 
+#ifndef PPC_FEATURE_CELL
+#define PPC_FEATURE_CELL 0x00010000
+#endif
+
 #ifndef PPC_FEATURE_BOOKE
 #define PPC_FEATURE_BOOKE 0x00008000
 #endif
@@ -1283,7 +1287,9 @@ ppc_linux_read_description (struct targe
     msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
     if (errno == 0 && msr < 0)
       {
-	if (vsx)
+	if (ppc_linux_get_hwcap () & PPC_FEATURE_CELL)
+	  return tdesc_powerpc_cell64l;
+	else if (vsx)
 	  return tdesc_powerpc_vsx64l;
 	else if (altivec)
 	  return tdesc_powerpc_altivec64l;
@@ -1293,7 +1299,9 @@ ppc_linux_read_description (struct targe
   }
 #endif
 
-  if (vsx)
+  if (ppc_linux_get_hwcap () & PPC_FEATURE_CELL)
+    return tdesc_powerpc_cell32l;
+  else if (vsx)
     return tdesc_powerpc_vsx32l;
   else if (altivec)
     return tdesc_powerpc_altivec32l;
diff -urNp gdb-orig/gdb/ppc-linux-tdep.c gdb-head/gdb/ppc-linux-tdep.c
--- gdb-orig/gdb/ppc-linux-tdep.c	2008-08-27 18:35:05.000000000 +0200
+++ gdb-head/gdb/ppc-linux-tdep.c	2008-09-07 23:22:02.132216406 +0200
@@ -38,12 +38,20 @@
 #include "trad-frame.h"
 #include "frame-unwind.h"
 #include "tramp-frame.h"
+#include "observer.h"
+#include "auxv.h"
+#include "elf/common.h"
+#include "exceptions.h"
+#include "arch-utils.h"
+#include "spu-tdep.h"
 
 #include "features/rs6000/powerpc-32l.c"
 #include "features/rs6000/powerpc-altivec32l.c"
+#include "features/rs6000/powerpc-cell32l.c"
 #include "features/rs6000/powerpc-vsx32l.c"
 #include "features/rs6000/powerpc-64l.c"
 #include "features/rs6000/powerpc-altivec64l.c"
+#include "features/rs6000/powerpc-cell64l.c"
 #include "features/rs6000/powerpc-vsx64l.c"
 #include "features/rs6000/powerpc-e500l.c"
 
@@ -989,6 +997,46 @@ static struct tramp_frame ppc64_linux_si
 };
 
 
+/* Address to use for displaced stepping.  When debugging a stand-alone
+   SPU executable, entry_point_address () will point to an SPU local-store
+   address and is thus not usable as displaced stepping location.  We use
+   the auxiliary vector to determine the PowerPC-side entry point address
+   instead.  */
+
+static CORE_ADDR ppc_linux_entry_point_addr = 0;
+
+static void
+ppc_linux_inferior_created (struct target_ops *target, int from_tty)
+{
+  ppc_linux_entry_point_addr = 0;
+}
+
+static CORE_ADDR
+ppc_linux_displaced_step_location (struct gdbarch *gdbarch)
+{
+  if (ppc_linux_entry_point_addr == 0)
+    {
+      CORE_ADDR addr;
+
+      /* Determine entry point from target auxiliary vector.  */
+      if (target_auxv_search (&current_target, AT_ENTRY, &addr) <= 0)
+	error (_("Cannot find AT_ENTRY auxiliary vector entry."));
+
+      /* Make certain that the address points at real code, and not a
+	 function descriptor.  */
+      addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+						 &current_target);
+
+      /* Inferior calls also use the entry point as a breakpoint location.
+	 We don't want displaced stepping to interfere with those
+	 breakpoints, so leave space.  */
+      ppc_linux_entry_point_addr = addr + 2 * PPC_INSN_SIZE;
+    }
+
+  return ppc_linux_entry_point_addr;
+}
+
+
 /* Return 1 if PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM are usable.  */
 int
 ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
@@ -1022,11 +1070,18 @@ ppc_linux_write_pc (struct regcache *reg
     regcache_cooked_write_unsigned (regcache, PPC_TRAP_REGNUM, -1);
 }
 
+static int
+ppc_linux_spu_section (bfd *abfd, asection *asect, void *user_data)
+{
+  return strncmp (bfd_section_name (abfd, asect), "SPU/", 4) == 0;
+}
+
 static const struct target_desc *
 ppc_linux_core_read_description (struct gdbarch *gdbarch,
 				 struct target_ops *target,
 				 bfd *abfd)
 {
+  asection *cell = bfd_sections_find_if (abfd, ppc_linux_spu_section, NULL);
   asection *altivec = bfd_get_section_by_name (abfd, ".reg-ppc-vmx");
   asection *vsx = bfd_get_section_by_name (abfd, ".reg-ppc-vsx");
   asection *section = bfd_get_section_by_name (abfd, ".reg");
@@ -1036,7 +1091,9 @@ ppc_linux_core_read_description (struct 
   switch (bfd_section_size (abfd, section))
     {
     case 48 * 4:
-      if (vsx)
+      if (cell)
+	return tdesc_powerpc_cell32l;
+      else if (vsx)
 	return tdesc_powerpc_vsx32l;
       else if (altivec)
 	return tdesc_powerpc_altivec32l;
@@ -1044,7 +1101,9 @@ ppc_linux_core_read_description (struct 
 	return tdesc_powerpc_32l;
 
     case 48 * 8:
-      if (vsx)
+      if (cell)
+	return tdesc_powerpc_cell64l;
+      else if (vsx)
 	return tdesc_powerpc_vsx64l;
       else if (altivec)
 	return tdesc_powerpc_altivec64l;
@@ -1056,6 +1115,249 @@ ppc_linux_core_read_description (struct 
     }
 }
 
+
+/* Cell/B.E. active SPE context tracking support.  */
+
+static CORE_ADDR spe_context_lm_addr = 0;
+static CORE_ADDR spe_context_offset = 0;
+
+static ptid_t spe_context_cache_ptid;
+static CORE_ADDR spe_context_cache_address;
+
+/* Callback for new objfiles.  We check whether we've loaded a version
+   of libspe2 that provides the __spe_current_active_context variable.  */
+static void
+ppc_linux_new_objfile (struct objfile *objfile)
+{
+  struct minimal_symbol *sym;
+
+  if (!objfile)
+    {
+      spe_context_lm_addr = 0;
+      spe_context_offset = 0;
+      spe_context_cache_ptid = minus_one_ptid;
+      spe_context_cache_address = 0;
+      return;
+    }
+
+  sym = lookup_minimal_symbol ("__spe_current_active_context", NULL, objfile);
+  if (sym)
+    {
+      spe_context_lm_addr = svr4_fetch_objfile_link_map (objfile);
+      spe_context_offset = SYMBOL_VALUE_ADDRESS (sym);
+      spe_context_cache_ptid = minus_one_ptid;
+      spe_context_cache_address = 0;
+      return;
+    }
+}
+
+/* Retrieve contents of the N'th element in the current thread's
+   linked SPE context list into ID and NPC.  Return the address of
+   said context element, or 0 if not found.  */
+static CORE_ADDR
+ppc_linux_spe_context (int wordsize, int n, int *id, unsigned int *npc)
+{
+  CORE_ADDR spe_context = 0;
+  gdb_byte buf[16];
+  int i;
+
+  /* Quick exit if we have not found __spe_current_active_context.  */
+  if (!spe_context_lm_addr)
+    return 0;
+
+  /* Look up cached address of thread-local variable.  */
+  if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
+    {
+      volatile struct gdb_exception ex;
+
+      if (!target_get_thread_local_address_p ())
+	return 0;
+
+      TRY_CATCH (ex, RETURN_MASK_ERROR)
+	{
+	  spe_context_cache_address
+	    = target_get_thread_local_address
+	       (inferior_ptid, spe_context_lm_addr, spe_context_offset);
+
+	  spe_context_cache_ptid = inferior_ptid;
+	}
+
+      if (ex.reason < 0)
+	return 0;
+    }
+
+  /* Read variable value.  */
+  if (target_read_memory (spe_context_cache_address, buf, wordsize) == 0)
+    spe_context = extract_unsigned_integer (buf, wordsize);
+
+  /* Cyle through to N'th linked list element.  */
+  for (i = 0; i < n && spe_context; i++)
+    if (target_read_memory (spe_context + align_up (12, wordsize),
+			    buf, wordsize) == 0)
+      spe_context = extract_unsigned_integer (buf, wordsize);
+    else
+      spe_context = 0;
+
+  /* Read current context.  */
+  if (spe_context
+      && target_read_memory (spe_context, buf, 12) != 0)
+    spe_context = 0;
+
+  /* Extract data elements.  */
+  if (spe_context)
+    {
+      if (id)
+	*id = extract_signed_integer (buf, 4);
+      if (npc)
+	*npc = extract_unsigned_integer (buf + 4, 4);
+    }
+
+  return spe_context;
+}
+
+
+/* Cell/B.E. cross-architecture unwinder support.  */
+
+struct ppu2spu_cache
+{
+  struct frame_id frame_id;
+  struct regcache *regcache;
+};
+
+static struct gdbarch *
+ppu2spu_prev_arch (struct frame_info *this_frame, void **this_cache)
+{
+  struct ppu2spu_cache *cache = *this_cache;
+  return get_regcache_arch (cache->regcache);
+}
+
+static void
+ppu2spu_this_id (struct frame_info *this_frame,
+		 void **this_cache, struct frame_id *this_id)
+{
+  struct ppu2spu_cache *cache = *this_cache;
+  *this_id = cache->frame_id;
+}
+
+static struct value *
+ppu2spu_prev_register (struct frame_info *this_frame,
+		       void **this_cache, int regnum)
+{
+  struct ppu2spu_cache *cache = *this_cache;
+  struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
+  gdb_byte *buf;
+
+  buf = alloca (register_size (gdbarch, regnum));
+  regcache_cooked_read (cache->regcache, regnum, buf);
+  return frame_unwind_got_bytes (this_frame, regnum, buf);
+}
+
+struct ppu2spu_data
+{
+  int id;
+  unsigned int npc;
+  gdb_byte gprs[128*16];
+};
+
+static int
+ppu2spu_unwind_register (void *src, int regnum, gdb_byte *buf)
+{
+  struct ppu2spu_data *data = src;
+
+  if (regnum >= 0 && regnum < SPU_NUM_GPRS)
+    memcpy (buf, data->gprs + 16*regnum, 16);
+  else if (regnum == SPU_ID_REGNUM)
+    store_unsigned_integer (buf, 4, data->id);
+  else if (regnum == SPU_PC_REGNUM)
+    store_unsigned_integer (buf, 4, data->npc);
+  else
+    return 0;
+
+  return 1;
+}
+
+static int
+ppu2spu_sniffer (const struct frame_unwind *self,
+		 struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct ppu2spu_data data;
+  struct frame_info *fi;
+  CORE_ADDR base, func, backchain, spe_context;
+  gdb_byte buf[8];
+  int n = 0;
+
+  /* Count the number of SPU contexts already in the frame chain.  */
+  for (fi = get_next_frame (this_frame); fi; fi = get_next_frame (fi))
+    if (get_frame_type (fi) == ARCH_FRAME
+	&& gdbarch_bfd_arch_info (get_frame_arch (fi))->arch == bfd_arch_spu)
+      n++;
+
+  base = get_frame_sp (this_frame);
+  func = get_frame_pc (this_frame);
+  if (target_read_memory (base, buf, tdep->wordsize))
+    return 0;
+  backchain = extract_unsigned_integer (buf, tdep->wordsize);
+
+  spe_context = ppc_linux_spe_context (tdep->wordsize, n, &data.id, &data.npc);
+  if (spe_context && base <= spe_context && spe_context < backchain)
+    {
+      struct gdbarch *spu_gdbarch;
+      char annex[32];
+
+      /* Find gdbarch for SPU.  */
+      struct gdbarch_info info;
+      gdbarch_info_init (&info);
+      info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
+      info.byte_order = BFD_ENDIAN_BIG;
+      info.osabi = GDB_OSABI_LINUX;
+      info.tdep_info = (void *) &data.id;
+      spu_gdbarch = gdbarch_find_by_info (info);
+      if (!spu_gdbarch)
+	return 0;
+
+      xsnprintf (annex, sizeof annex, "%d/regs", data.id);
+      if (target_read (&current_target, TARGET_OBJECT_SPU, annex,
+		       data.gprs, 0, sizeof data.gprs)
+	  == sizeof data.gprs)
+	{
+	  struct ppu2spu_cache *cache
+	    = FRAME_OBSTACK_CALLOC (1, struct ppu2spu_cache);
+
+	  struct regcache *regcache = regcache_xmalloc (spu_gdbarch);
+	  struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+	  regcache_save (regcache, ppu2spu_unwind_register, &data);
+	  discard_cleanups (cleanups);
+
+	  cache->frame_id = frame_id_build (base, func);
+	  cache->regcache = regcache;
+	  *this_prologue_cache = cache;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+static void
+ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache)
+{
+  struct ppu2spu_cache *cache = this_cache;
+  regcache_xfree (cache->regcache);
+}
+
+static const struct frame_unwind ppu2spu_unwind = {
+  ARCH_FRAME,
+  ppu2spu_this_id,
+  ppu2spu_prev_register,
+  NULL,
+  ppu2spu_sniffer,
+  ppu2spu_dealloc_cache,
+  ppu2spu_prev_arch,
+};
+
+
 static void
 ppc_linux_init_abi (struct gdbarch_info info,
                     struct gdbarch *gdbarch)
@@ -1096,6 +1398,12 @@ ppc_linux_init_abi (struct gdbarch_info 
       /* Trampolines.  */
       tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
       tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
+
+      /* BFD target for core files.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+	set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpcle");
+      else
+	set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
     }
   
   if (tdep->wordsize == 8)
@@ -1113,6 +1421,12 @@ ppc_linux_init_abi (struct gdbarch_info 
       /* Trampolines.  */
       tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
       tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
+
+      /* BFD target for core files.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+	set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpcle");
+      else
+	set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
     }
   set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section);
   set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
@@ -1152,6 +1466,22 @@ ppc_linux_init_abi (struct gdbarch_info 
 				   PPC_TRAP_REGNUM, "trap");
 	}
     }
+
+  /* Enable Cell/B.E. if supported by the target.  */
+  if (tdesc_compatible_p (info.target_desc,
+			  bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu)))
+    {
+      /* Cell/B.E. multi-architecture support.  */
+      set_spu_solib_ops (gdbarch);
+
+      /* Cell/B.E. cross-architecture unwinder support.  */
+      frame_unwind_prepend_unwinder (gdbarch, &ppu2spu_unwind);
+
+      /* The default displaced_step_at_entry_point doesn't work for
+	 SPU stand-alone executables.  */
+      set_gdbarch_displaced_step_location (gdbarch,
+					   ppc_linux_displaced_step_location);
+    }
 }
 
 void
@@ -1166,12 +1496,20 @@ _initialize_ppc_linux_tdep (void)
   gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
                          ppc_linux_init_abi);
 
+  /* Attach to inferior_created observer.  */
+  observer_attach_inferior_created (ppc_linux_inferior_created);
+
+  /* Add ourselves to objfile event chain.  */
+  observer_attach_new_objfile (ppc_linux_new_objfile);
+
   /* Initialize the Linux target descriptions.  */
   initialize_tdesc_powerpc_32l ();
   initialize_tdesc_powerpc_altivec32l ();
+  initialize_tdesc_powerpc_cell32l ();
   initialize_tdesc_powerpc_vsx32l ();
   initialize_tdesc_powerpc_64l ();
   initialize_tdesc_powerpc_altivec64l ();
+  initialize_tdesc_powerpc_cell64l ();
   initialize_tdesc_powerpc_vsx64l ();
   initialize_tdesc_powerpc_e500l ();
 }
diff -urNp gdb-orig/gdb/ppc-linux-tdep.h gdb-head/gdb/ppc-linux-tdep.h
--- gdb-orig/gdb/ppc-linux-tdep.h	2008-08-21 21:44:32.000000000 +0200
+++ gdb-head/gdb/ppc-linux-tdep.h	2008-09-07 23:21:59.728163399 +0200
@@ -41,10 +41,12 @@ int ppc_linux_trap_reg_p (struct gdbarch
 /* Linux target descriptions.  */
 extern struct target_desc *tdesc_powerpc_32l;
 extern struct target_desc *tdesc_powerpc_altivec32l;
+extern struct target_desc *tdesc_powerpc_cell32l;
 extern struct target_desc *tdesc_powerpc_vsx32l;
 extern struct target_desc *tdesc_powerpc_e500l;
 extern struct target_desc *tdesc_powerpc_64l;
 extern struct target_desc *tdesc_powerpc_altivec64l;
+extern struct target_desc *tdesc_powerpc_cell64l;
 extern struct target_desc *tdesc_powerpc_vsx64l;
 
 #endif /* PPC_LINUX_TDEP_H */
diff -urNp gdb-orig/gdb/printcmd.c gdb-head/gdb/printcmd.c
--- gdb-orig/gdb/printcmd.c	2008-09-05 13:34:13.000000000 +0200
+++ gdb-head/gdb/printcmd.c	2008-09-07 23:21:56.843178286 +0200
@@ -373,7 +373,7 @@ print_scalar_formatted (const void *vala
   /* If we are printing it as unsigned, truncate it in case it is actually
      a negative signed value (e.g. "print/u (short)-1" should print 65535
      (if shorts are 16 bits) instead of 4294967295).  */
-  if (format != 'd')
+  if (format != 'd' || TYPE_UNSIGNED (type))
     {
       if (len < sizeof (LONGEST))
 	val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
diff -urNp gdb-orig/gdb/proc-service.c gdb-head/gdb/proc-service.c
--- gdb-orig/gdb/proc-service.c	2008-07-12 22:00:19.000000000 +0200
+++ gdb-head/gdb/proc-service.c	2008-09-07 23:21:51.595134281 +0200
@@ -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);
diff -urNp gdb-orig/gdb/regcache.c gdb-head/gdb/regcache.c
--- gdb-orig/gdb/regcache.c	2008-08-21 21:44:32.000000000 +0200
+++ gdb-head/gdb/regcache.c	2008-09-07 23:21:53.374145263 +0200
@@ -29,6 +29,7 @@
 #include "gdb_string.h"
 #include "gdbcmd.h"		/* For maintenanceprintlist.  */
 #include "observer.h"
+#include "arch-utils.h"
 
 /*
  * DATA STRUCTURE
@@ -410,36 +411,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;
+
+struct regcache *
+get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+{
+  struct regcache_list *list;
+  struct regcache *new_regcache;
 
-  if (current_regcache && ptid_equal (current_regcache->ptid, ptid)
-      && get_regcache_arch (current_regcache) == thread_gdbarch)
-    return 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;
 
-  if (current_regcache)
-    regcache_xfree (current_regcache);
+  new_regcache = regcache_xmalloc (gdbarch);
+  new_regcache->readonly_p = 0;
+  new_regcache->ptid = ptid;
 
-  current_regcache = regcache_xmalloc (thread_gdbarch);
-  current_regcache->readonly_p = 0;
-  current_regcache->ptid = ptid;
+  list = xmalloc (sizeof (struct regcache_list));
+  list->regcache = new_regcache;
+  list->next = current_regcache;
+  current_regcache = list;
 
-  return current_regcache;
+  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 +483,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 +504,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 ();
 
@@ -509,6 +545,8 @@ regcache_raw_read (struct regcache *regc
 	{
 	  struct cleanup *old_chain = save_inferior_ptid ();
 	  inferior_ptid = regcache->ptid;
+	  save_current_gdbarch ();
+	  current_gdbarch = get_regcache_arch (regcache);
 	  target_fetch_registers (regcache, regnum);
 	  do_cleanups (old_chain);
 	}
@@ -667,6 +705,8 @@ regcache_raw_write (struct regcache *reg
 
   old_chain = save_inferior_ptid ();
   inferior_ptid = regcache->ptid;
+  save_current_gdbarch ();
+  current_gdbarch = get_regcache_arch (regcache);
 
   target_prepare_to_store (regcache);
   memcpy (register_buffer (regcache, regnum), buf,
diff -urNp gdb-orig/gdb/regcache.h gdb-head/gdb/regcache.h
--- gdb-orig/gdb/regcache.h	2008-05-11 23:07:12.000000000 +0200
+++ gdb-head/gdb/regcache.h	2008-09-07 23:21:51.605132846 +0200
@@ -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);
diff -urNp gdb-orig/gdb/regformats/rs6000/powerpc-cell32l.dat gdb-head/gdb/regformats/rs6000/powerpc-cell32l.dat
--- gdb-orig/gdb/regformats/rs6000/powerpc-cell32l.dat	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/regformats/rs6000/powerpc-cell32l.dat	2008-09-07 23:21:59.735162394 +0200
@@ -0,0 +1,111 @@
+# DO NOT EDIT: generated from rs6000/powerpc-cell32l.xml
+name:powerpc_cell32l
+xmltarget:powerpc-cell32l.xml
+expedite:r1,pc,r0,orig_r3,r4
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:r15
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:r26
+32:r27
+32:r28
+32:r29
+32:r30
+32:r31
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
+64:f16
+64:f17
+64:f18
+64:f19
+64:f20
+64:f21
+64:f22
+64:f23
+64:f24
+64:f25
+64:f26
+64:f27
+64:f28
+64:f29
+64:f30
+64:f31
+32:pc
+32:msr
+32:cr
+32:lr
+32:ctr
+32:xer
+32:fpscr
+32:orig_r3
+32:trap
+128:vr0
+128:vr1
+128:vr2
+128:vr3
+128:vr4
+128:vr5
+128:vr6
+128:vr7
+128:vr8
+128:vr9
+128:vr10
+128:vr11
+128:vr12
+128:vr13
+128:vr14
+128:vr15
+128:vr16
+128:vr17
+128:vr18
+128:vr19
+128:vr20
+128:vr21
+128:vr22
+128:vr23
+128:vr24
+128:vr25
+128:vr26
+128:vr27
+128:vr28
+128:vr29
+128:vr30
+128:vr31
+32:vscr
+32:vrsave
diff -urNp gdb-orig/gdb/regformats/rs6000/powerpc-cell64l.dat gdb-head/gdb/regformats/rs6000/powerpc-cell64l.dat
--- gdb-orig/gdb/regformats/rs6000/powerpc-cell64l.dat	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/regformats/rs6000/powerpc-cell64l.dat	2008-09-07 23:21:59.739161820 +0200
@@ -0,0 +1,111 @@
+# DO NOT EDIT: generated from rs6000/powerpc-cell64l.xml
+name:powerpc_cell64l
+xmltarget:powerpc-cell64l.xml
+expedite:r1,pc,r0,orig_r3,r4
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
+64:f16
+64:f17
+64:f18
+64:f19
+64:f20
+64:f21
+64:f22
+64:f23
+64:f24
+64:f25
+64:f26
+64:f27
+64:f28
+64:f29
+64:f30
+64:f31
+64:pc
+64:msr
+32:cr
+64:lr
+64:ctr
+32:xer
+32:fpscr
+64:orig_r3
+64:trap
+128:vr0
+128:vr1
+128:vr2
+128:vr3
+128:vr4
+128:vr5
+128:vr6
+128:vr7
+128:vr8
+128:vr9
+128:vr10
+128:vr11
+128:vr12
+128:vr13
+128:vr14
+128:vr15
+128:vr16
+128:vr17
+128:vr18
+128:vr19
+128:vr20
+128:vr21
+128:vr22
+128:vr23
+128:vr24
+128:vr25
+128:vr26
+128:vr27
+128:vr28
+128:vr29
+128:vr30
+128:vr31
+32:vscr
+32:vrsave
diff -urNp gdb-orig/gdb/remote.c gdb-head/gdb/remote.c
--- gdb-orig/gdb/remote.c	2008-08-27 15:20:46.000000000 +0200
+++ gdb-head/gdb/remote.c	2008-09-07 23:21:55.496107156 +0200
@@ -3575,6 +3575,7 @@ Packet: '%s'\n"),
 		else
 		  {
 		    struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+		    struct regcache *regcache;
 		    p = p1;
 
 		    if (*p != ':')
@@ -3595,8 +3596,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 != ';')
@@ -5392,7 +5395,7 @@ remote_insert_breakpoint (struct bp_targ
       switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_Z0]))
 	{
 	case PACKET_ERROR:
-	  return -1;
+	  return 1;
 	case PACKET_OK:
 	  bp_tgt->placed_address = addr;
 	  bp_tgt->placed_size = bpsize;
@@ -5579,7 +5582,7 @@ remote_insert_hw_breakpoint (struct bp_t
     (target_gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
 
   if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
-    return -1;
+    return 1;
 
   rs = get_remote_state ();
   p = rs->buf;
@@ -5599,7 +5602,7 @@ remote_insert_hw_breakpoint (struct bp_t
     {
     case PACKET_ERROR:
     case PACKET_UNKNOWN:
-      return -1;
+      return 1;
     case PACKET_OK:
       return 0;
     }
@@ -5616,7 +5619,7 @@ remote_remove_hw_breakpoint (struct bp_t
   char *p = rs->buf;
 
   if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
-    return -1;
+    return 1;
 
   *(p++) = 'z';
   *(p++) = '1';
@@ -5633,7 +5636,7 @@ remote_remove_hw_breakpoint (struct bp_t
     {
     case PACKET_ERROR:
     case PACKET_UNKNOWN:
-      return -1;
+      return 1;
     case PACKET_OK:
       return 0;
     }
diff -urNp gdb-orig/gdb/sentinel-frame.c gdb-head/gdb/sentinel-frame.c
--- gdb-orig/gdb/sentinel-frame.c	2008-05-01 01:20:00.000000000 +0200
+++ gdb-head/gdb/sentinel-frame.c	2008-09-07 23:21:52.603122335 +0200
@@ -76,11 +76,23 @@ sentinel_frame_this_id (struct frame_inf
   internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
 }
 
+static struct gdbarch *
+sentinel_frame_prev_arch (struct frame_info *this_frame,
+			  void **this_prologue_cache)
+{
+  struct frame_unwind_cache *cache = *this_prologue_cache;
+  return get_regcache_arch (cache->regcache);
+}
+
 const struct frame_unwind sentinel_frame_unwinder =
 {
   SENTINEL_FRAME,
   sentinel_frame_this_id,
-  sentinel_frame_prev_register
+  sentinel_frame_prev_register,
+  NULL,
+  NULL,
+  NULL,
+  sentinel_frame_prev_arch,
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
diff -urNp gdb-orig/gdb/solib.c gdb-head/gdb/solib.c
--- gdb-orig/gdb/solib.c	2008-08-26 19:22:08.000000000 +0200
+++ gdb-head/gdb/solib.c	2008-09-07 23:21:54.733216671 +0200
@@ -311,15 +311,22 @@ static int
 solib_map_sections (void *arg)
 {
   struct so_list *so = (struct so_list *) arg;	/* catch_errors bogon */
+  struct target_so_ops *ops = solib_ops (target_gdbarch);
   char *filename;
   struct section_table *p;
   struct cleanup *old_chain;
-  bfd *abfd;
+  bfd *abfd = NULL;
+
+  if (ops->open_bfd)
+    abfd = ops->open_bfd (so->so_name);
 
-  filename = tilde_expand (so->so_name);
-  old_chain = make_cleanup (xfree, filename);
-  abfd = solib_bfd_open (filename);
-  do_cleanups (old_chain);
+  if (!abfd)
+    {
+      filename = tilde_expand (so->so_name);
+      old_chain = make_cleanup (xfree, filename);
+      abfd = solib_bfd_open (filename);
+      do_cleanups (old_chain);
+    }
 
   /* Leave bfd open, core_xfer_memory and "info files" need it.  */
   so->abfd = abfd;
@@ -338,8 +345,6 @@ solib_map_sections (void *arg)
 
   for (p = so->sections; p < so->sections_end; p++)
     {
-      struct target_so_ops *ops = solib_ops (target_gdbarch);
-
       /* Relocate the section binding addresses as recorded in the shared
          object's file by the base address to which the object was actually
          mapped. */
@@ -420,7 +425,9 @@ static int
 symbol_add_stub (void *arg)
 {
   struct so_list *so = (struct so_list *) arg;  /* catch_errs bogon */
+  struct target_so_ops *ops = solib_ops (target_gdbarch);
   struct section_addr_info *sap;
+  bfd *abfd = NULL;
 
   /* Have we already loaded this shared object?  */
   ALL_OBJFILES (so->objfile)
@@ -429,11 +436,18 @@ symbol_add_stub (void *arg)
 	return 1;
     }
 
+  /* Open a second BFD for this file.  */
+  if (ops->open_bfd)
+    abfd = ops->open_bfd (so->so_name);
+
+  if (!abfd)
+    abfd = symfile_bfd_open (so->so_name);
+
   sap = build_section_addr_info_from_section_table (so->sections,
                                                     so->sections_end);
 
-  so->objfile = symbol_file_add (so->so_name, so->from_tty,
-				 sap, 0, OBJF_SHARED);
+  so->objfile = symbol_file_add_from_bfd (abfd, so->from_tty,
+					  sap, 0, OBJF_SHARED);
   free_section_addr_info (sap);
 
   return (1);
diff -urNp gdb-orig/gdb/solib-spu.c gdb-head/gdb/solib-spu.c
--- gdb-orig/gdb/solib-spu.c	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/solib-spu.c	2008-09-07 23:22:00.512183604 +0200
@@ -0,0 +1,477 @@
+/* Cell SPU GNU/Linux support -- shared library handling.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "gdb_stat.h"
+#include "arch-utils.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "solib.h"
+#include "solib-svr4.h"
+#include "solist.h"
+#include "inferior.h"
+#include "objfiles.h"
+#include "observer.h"
+
+#include "spu-tdep.h"
+
+/* Highest SPE id (file handle) the inferior may have.  */
+#define MAX_SPE_FD 1024
+
+/* Stand-alone SPE executable?  */
+#define spu_standalone_p() \
+  (symfile_objfile && symfile_objfile->obfd \
+   && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
+
+
+/* Relocate main SPE executable.  */
+static void spu_relocate_main_executable (int spufs_fd)
+{
+  struct objfile *objfile;
+  struct cleanup *old_chain;
+  struct section_offsets *new_offsets;
+  int i;
+
+  for (objfile = symfile_objfile;
+       objfile;
+       objfile = objfile->separate_debug_objfile)
+    {
+      new_offsets = xcalloc (objfile->num_sections,
+			     sizeof (struct section_offsets));
+      old_chain = make_cleanup (xfree, new_offsets);
+
+      for (i = 0; i < objfile->num_sections; i++)
+        new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
+
+      objfile_relocate (objfile, new_offsets);
+      do_cleanups (old_chain);
+    }
+}
+
+/* When running a stand-alone SPE executable, we need to skip one more
+   exec event on startup, to get past the binfmt_misc loader.  */
+static void
+spu_skip_standalone_loader (void)
+{
+  if (target_has_execution)
+    {
+      struct cleanup *old_chain;
+
+      /* Suppress MI messages that are unexpected at this point.  */
+      old_chain = make_cleanup_restore_integer (&suppress_resume_observer);
+      suppress_resume_observer = 1;
+      make_cleanup_restore_integer (&suppress_stop_observer);
+      suppress_stop_observer = 1;
+
+      /* We either may or may not have an extra SIGTRAP pending, depending
+	 on whether we've started a new inferior or attached to one that was
+	 already running.  We cannot readily distinguish between the two,
+	 in particular when using the extended-remote target.  Thus, we pass
+	 TARGET_SIGNAL_TRAP to resume -- this way we will always get a trap.
+	 (If one was already pending, it will be combined into this trap.)  */
+      stop_soon = STOP_QUIETLY;
+      resume (0, TARGET_SIGNAL_TRAP);
+      wait_for_inferior (1);
+      stop_soon = NO_STOP_QUIETLY;
+
+      do_cleanups (old_chain);
+    }
+}
+
+/* Build a list of `struct so_list' objects describing the shared
+   objects currently loaded in the inferior.  */
+static struct so_list *
+spu_current_sos (void)
+{
+  struct so_list *head;
+  struct so_list **link_ptr;
+
+  char buf[MAX_SPE_FD * 4];
+  int i, size;
+
+  /* First, retrieve the SVR4 shared library list.  Switch to the
+     PPE architecture while doing so.  This should not be strictly
+     necessary, but it is right now.  */
+  struct cleanup *old_chain = save_current_gdbarch ();
+  current_gdbarch = target_gdbarch;
+  head = svr4_so_ops.current_sos ();
+  do_cleanups (old_chain);
+
+  /* Append our libraries to the end of the list.  */
+  for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next)
+    ;
+
+  /* Determine list of SPU ids.  */
+  size = target_read (&current_target, TARGET_OBJECT_SPU, NULL,
+		      buf, 0, sizeof buf);
+
+  /* Do not add stand-alone SPE executable context as shared library,
+     but relocate main SPE executable objfile.  */
+  if (spu_standalone_p ())
+    {
+      if (size == 4)
+	spu_relocate_main_executable (extract_unsigned_integer (buf, 4));
+
+      return head;
+    }
+
+  /* As soon as any SPE context exists in the inferior, we have to
+     enable SPU multi-architecture target support.  */
+  if (size > 0)
+    spu_multiarch_enable ();
+  else
+    spu_multiarch_disable ();
+
+  /* Create an so_list entry for each SPU id.  */
+  for (i = 0; i < size; i += 4)
+    {
+      int fd = extract_unsigned_integer (buf + i, 4);
+      struct so_list *new;
+
+      unsigned long long addr;
+      char annex[32], id[100];
+      int len;
+
+      /* Read object ID.  There's a race window where the inferior may have
+	 already created the SPE context, but not installed the object-id
+	 yet.  Skip such entries; we'll be back for them later.  */
+      xsnprintf (annex, sizeof annex, "%d/object-id", fd);
+      len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+			 id, 0, sizeof id);
+      if (len <= 0 || len >= sizeof id)
+	continue;
+      id[len] = 0;
+      if (sscanf (id, "0x%llx", &addr) != 1 || !addr)
+	continue;
+
+      /* Allocate so_list structure.  */
+      new = XZALLOC (struct so_list);
+
+      /* Encode FD and object ID in path name.  Choose the name so as not
+	 to conflict with any (normal) SVR4 library path name.  */
+      xsnprintf (new->so_name, sizeof new->so_name, "@0x%llx <%d>", addr, fd);
+      strcpy (new->so_original_name, new->so_name);
+
+      *link_ptr = new;
+      link_ptr = &new->next;
+    }
+
+  return head;
+}
+
+/* Free so_list information.  */
+static void
+spu_free_so (struct so_list *so)
+{
+  if (so->so_original_name[0] != '@')
+    svr4_so_ops.free_so (so);
+}
+
+/* Relocate section addresses.  */
+static void
+spu_relocate_section_addresses (struct so_list *so,
+				struct section_table *sec)
+{
+  if (so->so_original_name[0] != '@')
+    svr4_so_ops.relocate_section_addresses (so, sec);
+  else
+    {
+      unsigned long long addr;
+      int fd;
+
+      /* Set addr_low/high to just LS offset for display.  */
+      if (so->addr_low == 0 && so->addr_high == 0
+          && strcmp (sec->the_bfd_section->name, ".text") == 0)
+        {
+          so->addr_low = sec->addr;
+          so->addr_high = sec->endaddr;
+        }
+
+      /* Decode object ID.  */
+      if (sscanf (so->so_original_name, "@0x%llx <%d>", &addr, &fd) != 2)
+	internal_error (__FILE__, __LINE__, "bad object ID");
+
+      sec->addr = SPUADDR (fd, sec->addr);
+      sec->endaddr = SPUADDR (fd, sec->endaddr);
+    }
+}
+
+
+/* Inferior memory should contain an SPE executable image at location ADDR.
+   Allocate a BFD representing that executable.  Return NULL on error.  */
+
+static void *
+spu_bfd_iovec_open (bfd *nbfd, void *open_closure)
+{
+  return open_closure;
+}
+
+static int
+spu_bfd_iovec_close (bfd *nbfd, void *stream)
+{
+  xfree (stream);
+  return 1;
+}
+
+static file_ptr
+spu_bfd_iovec_pread (bfd *abfd, void *stream, void *buf,
+                     file_ptr nbytes, file_ptr offset)
+{
+  CORE_ADDR addr = *(CORE_ADDR *)stream;
+  int ret;
+
+  /* Switch to the PPE architecture while reading target memory.
+     This should not be necessary, but it is right now.  */
+  struct cleanup *old_chain = save_current_gdbarch ();
+  current_gdbarch = target_gdbarch;
+  ret = target_read_memory (addr + offset, buf, nbytes);
+  do_cleanups (old_chain);
+
+  if (ret != 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  return nbytes;
+}
+
+static int
+spu_bfd_iovec_stat (bfd *abfd, void *stream, struct stat *sb)
+{
+  /* We don't have an easy way of finding the size of embedded spu
+     images.  We could parse the in-memory ELF header and section
+     table to find the extent of the last section but that seems
+     pointless when the size is needed only for checks of other
+     parsed values in dbxread.c.  */
+  sb->st_size = INT_MAX;
+  return 0;
+}
+
+static bfd *
+spu_bfd_open (char *name, CORE_ADDR addr)
+{
+  bfd *nbfd;
+
+  CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
+  *open_closure = addr;
+
+  nbfd = bfd_openr_iovec (xstrdup (name), "elf32-spu",
+                          spu_bfd_iovec_open, open_closure,
+                          spu_bfd_iovec_pread, spu_bfd_iovec_close,
+			  spu_bfd_iovec_stat);
+  if (!nbfd)
+    return NULL;
+
+  if (!bfd_check_format (nbfd, bfd_object))
+    {
+      bfd_close (nbfd);
+      return NULL;
+    }
+
+  return nbfd;
+}
+
+/* Open shared library BFD.  */
+static bfd *
+spu_open_bfd (char *pathname)
+{
+  char *original_name = strrchr (pathname, '@');
+  char name[64];
+  bfd *abfd;
+  asection *spu_name;
+  unsigned long long addr;
+  int fd;
+
+  if (!original_name)
+    return NULL;
+
+  /* Decode object ID.  */
+  if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2)
+    internal_error (__FILE__, __LINE__, "bad object ID");
+
+  /* Open BFD representing SPE executable.  */
+  abfd = spu_bfd_open (original_name, (CORE_ADDR) addr);
+  if (!abfd)
+    error (_("Cannot read SPE executable at %s"), original_name);
+
+  /* Retrieve SPU name note.  */
+  spu_name = bfd_get_section_by_name (abfd, ".note.spu_name");
+  if (spu_name)
+    {
+      int sect_size = bfd_section_size (abfd, spu_name);
+      if (sect_size > 20)
+	{
+	  char *buf = alloca (sect_size - 20 + strlen (original_name) + 1);
+	  bfd_get_section_contents (abfd, spu_name, buf, 20, sect_size - 20);
+	  buf[sect_size - 20] = '\0';
+
+	  strcat (buf, original_name);
+
+	  xfree ((char *)abfd->filename);
+	  abfd->filename = xstrdup (buf);
+	}
+    }
+
+  return abfd;
+}
+
+/* Lookup global symbol in a SPE executable.  */
+static struct symbol *
+spu_lookup_lib_symbol (const struct objfile *objfile,
+		       const char *name,
+		       const char *linkage_name,
+		       const domain_enum domain)
+{
+  if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
+    return lookup_global_symbol_from_objfile (objfile, name, linkage_name,
+					      domain);
+
+  if (svr4_so_ops.lookup_lib_global_symbol != NULL)
+    return svr4_so_ops.lookup_lib_global_symbol (objfile, name, linkage_name,
+						 domain);
+  return NULL;
+}
+
+/* Enable shared library breakpoint.  */
+static int
+spu_enable_break (struct objfile *objfile)
+{
+  struct minimal_symbol *spe_event_sym = NULL;
+
+  /* The libspe library will call __spe_context_update_event whenever any
+     SPE context is allocated or destroyed.  */
+  spe_event_sym = lookup_minimal_symbol ("__spe_context_update_event",
+					 NULL, objfile);
+
+  /* Place a solib_event breakpoint on the symbol.  */
+  if (spe_event_sym)
+    {
+      CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
+      addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, addr,
+                                                 &current_target);
+      create_solib_event_breakpoint (addr);
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Create inferior hook.  */
+static void
+spu_solib_create_inferior_hook (void)
+{
+  /* Remove all previously installed solib breakpoints.  Both the SVR4
+     code and us will re-install all required breakpoints.  */
+  remove_solib_event_breakpoints ();
+
+  /* Handle SPE stand-alone executables.  */
+  if (spu_standalone_p ())
+    {
+      /* After an SPE stand-alone executable was loaded, we'll receive
+	 an additional trap due to the binfmt_misc handler.  Make sure
+	 to skip that trap.  */
+      spu_skip_standalone_loader ();
+
+      /* At this point, the target is executing, so GDB expects to be
+	 able to read/write target memory.  For the stand-alone case,
+	 "target memory" is actually the local store of the stand-alone
+	 SPE context -- but at this point this context has not yet been
+	 allocated.  This is a problem in particular for breakpoints that
+	 may already have been established.
+
+	 We solve this by installing the multi-architecture handler
+	 already at this point.  This target will understand that
+	 breakpoints falling the range of addresses covered by the
+	 SPE local store need to be ignored.
+
+	 (Note that this needs to be done here, before the solib code gets
+	 active -- otherwise we'd fail on the first breakpoint_re_set call
+	 triggered when new shared libraries are found.)
+
+	 Once the actual stand-alone SPE context is installed, spu_current_sos
+	 will detect this and relocate the main executable to its final (valid)
+	 address range.  Breakpoints will be automatically re-inserted at
+	 that point.  */
+      spu_multiarch_enable ();
+
+      /* A special case arises when re-starting an executable, because at
+	 this point it still resides at the relocated address range that was
+	 determined during its last execution.  We need to undo the relocation
+	 so that that multi-architecture target recognizes the stand-alone
+	 initialization special case.  */
+      spu_relocate_main_executable (-1);
+    }
+
+  /* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints.  */
+  svr4_so_ops.solib_create_inferior_hook ();
+
+  /* If the inferior is statically linked against libspe, we need to install
+     our own solib breakpoint right now.  Otherwise, it will be installed by
+     the solib_loaded observer below as soon as libspe is loaded.  */
+  spu_enable_break (NULL);
+}
+
+/* Install SPE "shared library" handling.  This is called by -tdep code
+   that wants to support SPU as a secondary architecture.  */
+void
+set_spu_solib_ops (struct gdbarch *gdbarch)
+{
+  static struct target_so_ops spu_so_ops;
+
+  /* Initialize this lazily, to avoid an initialization order
+     dependency on solib-svr4.c's _initialize routine.  */
+  if (spu_so_ops.current_sos == NULL)
+    {
+      spu_so_ops = svr4_so_ops;
+      spu_so_ops.solib_create_inferior_hook = spu_solib_create_inferior_hook;
+      spu_so_ops.relocate_section_addresses = spu_relocate_section_addresses;
+      spu_so_ops.free_so = spu_free_so;
+      spu_so_ops.current_sos = spu_current_sos;
+      spu_so_ops.open_bfd = spu_open_bfd;
+      spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
+    }
+
+  set_solib_ops (gdbarch, &spu_so_ops);
+}
+
+/* Observer for the solib_loaded event.  Used to install our breakpoint
+   if libspe is a shared library.  */
+static void
+spu_solib_loaded (struct so_list *so)
+{
+  if (strstr (so->so_original_name, "/libspe") != NULL)
+    {
+      solib_read_symbols (so, so->from_tty);
+      spu_enable_break (so->objfile);
+    }
+}
+
+void
+_initialize_spu_solib (void)
+{
+  observer_attach_solib_loaded (spu_solib_loaded);
+}
+
diff -urNp gdb-orig/gdb/solist.h gdb-head/gdb/solist.h
--- gdb-orig/gdb/solist.h	2008-08-26 19:22:08.000000000 +0200
+++ gdb-head/gdb/solist.h	2008-09-07 23:21:54.738215953 +0200
@@ -118,6 +118,10 @@ struct target_so_ops
        and another from the list returned by current_sos, return 1
        if they represent the same library.  */
     int (*same) (struct so_list *gdb, struct so_list *inferior);
+
+    /* Extra hook for opening a BFD for a solib.  Can be used to
+       retrieve solibs from inferior memory instead of from files.  */
+    bfd *(*open_bfd) (char *pathname);
   };
 
 /* Free the memory associated with a (so_list *).  */
diff -urNp gdb-orig/gdb/sol-thread.c gdb-head/gdb/sol-thread.c
--- gdb-orig/gdb/sol-thread.c	2008-08-21 21:44:32.000000000 +0200
+++ gdb-head/gdb/sol-thread.c	2008-09-07 23:21:51.661124808 +0200
@@ -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)
diff -urNp gdb-orig/gdb/spu-multiarch.c gdb-head/gdb/spu-multiarch.c
--- gdb-orig/gdb/spu-multiarch.c	1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/spu-multiarch.c	2008-09-07 23:22:00.519182599 +0200
@@ -0,0 +1,450 @@
+/* Cell SPU GNU/Linux multi-architecture debugging support.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "observer.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "block.h"
+#include "exec.h"
+#include "target-descriptions.h"
+
+#include "ppc-tdep.h"
+#include "ppc-linux-tdep.h"
+#include "spu-tdep.h"
+
+/* This module's target vector.  */
+static struct target_ops spu_ops;
+
+/* Stand-alone SPE executable?  */
+#define spu_standalone_p() \
+  (symfile_objfile && symfile_objfile->obfd \
+   && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
+
+/* PPU side system calls.  */
+#define INSTR_SC	0x44000002
+#define NR_spu_run	0x0116
+
+/* If the PPU thread is currently stopped on a spu_run system call,
+   return to FD and ADDR the file handle and NPC parameter address
+   used with the system call.  Return non-zero if successful.  */
+static int
+parse_spufs_run (ptid_t ptid, int *fd, CORE_ADDR *addr)
+{
+  struct gdbarch_tdep *tdep;
+  struct regcache *regcache;
+  char buf[4];
+  CORE_ADDR pc;
+  ULONGEST regval;
+
+  /* If we're not on PPU, there's nothing to detect.  */
+  if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_powerpc)
+    return 0;
+
+  /* Get PPU-side registers.  */
+  regcache = get_thread_arch_regcache (ptid, target_gdbarch);
+  tdep = gdbarch_tdep (target_gdbarch);
+
+  /* Fetch instruction preceding current NIP.  */
+  if (target_read_memory (regcache_read_pc (regcache) - 4, buf, 4) != 0)
+    return 0;
+  /* It should be a "sc" instruction.  */
+  if (extract_unsigned_integer (buf, 4) != INSTR_SC)
+    return 0;
+  /* System call number should be NR_spu_run.  */
+  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum, &regval);
+  if (regval != NR_spu_run)
+    return 0;
+
+  /* Register 3 contains fd, register 4 the NPC param pointer.  */
+  regcache_cooked_read_unsigned (regcache, PPC_ORIG_R3_REGNUM, &regval);
+  *fd = (int) regval;
+  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 4, &regval);
+  *addr = (CORE_ADDR) regval;
+  return 1;
+}
+
+/* Find gdbarch for SPU context SPUFS_FD.  */
+static struct gdbarch *
+spu_gdbarch (int spufs_fd)
+{
+  struct gdbarch_info info;
+  gdbarch_info_init (&info);
+  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
+  info.byte_order = BFD_ENDIAN_BIG;
+  info.osabi = GDB_OSABI_LINUX;
+  info.tdep_info = (void *) &spufs_fd;
+  return gdbarch_find_by_info (info);
+}
+
+/* Override the to_thread_architecture routine.  */
+static struct gdbarch *
+spu_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+  int spufs_fd;
+  ULONGEST spufs_addr;
+
+  if (parse_spufs_run (ptid, &spufs_fd, &spufs_addr))
+    return spu_gdbarch (spufs_fd);
+
+  return target_gdbarch;
+}
+
+/* Override the to_wait routine to detect current architecture.  */
+static ptid_t
+spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+
+  /* Always switch to PPU while running the inferior.  This allows
+     linux-thread-db.c code to work as expected.  */
+  current_gdbarch = target_gdbarch;
+
+  /* Run it.  */
+  ptid = ops_beneath->to_wait (ptid, ourstatus);
+
+  /* Detect and switch to current architecture.  */
+  if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
+    current_gdbarch = spu_thread_architecture (&current_target, ptid);
+
+  return ptid;
+}
+
+
+/* Override the to_region_ok_for_hw_watchpoint routine.  */
+static int
+spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+
+  while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
+    ops_beneath = find_target_beneath (ops_beneath);
+  gdb_assert (ops_beneath);
+
+  /* Ignore attempts to remove breakpoints in a stand-alone SPE
+     executable just after startup, before we know the FD.  */
+  if (spu_standalone_p () && addr < SPU_LS_SIZE)
+    return -1;
+
+  /* We cannot watch SPU local store.  */
+  if (SPUADDR_SPU (addr) != -1)
+    return 0;
+
+  if (ops_beneath)
+    return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len);
+
+  return 0;
+}
+
+/* Override the to_insert_breakpoint routine.  */
+static int
+spu_insert_breakpoint (struct bp_target_info *bp)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+  CORE_ADDR addr = bp->placed_address;
+  struct cleanup *old_chain;
+  int ret;
+
+  while (ops_beneath && !ops_beneath->to_insert_breakpoint)
+    ops_beneath = find_target_beneath (ops_beneath);
+  gdb_assert (ops_beneath);
+
+  /* Ignore attempts to insert breakpoints in a stand-alone SPE
+     executable just after startup, before we know the FD.  */
+  if (spu_standalone_p () && addr < SPU_LS_SIZE)
+    return -1;
+
+  old_chain = save_current_gdbarch ();
+  if (SPUADDR_SPU (addr) != -1)
+    current_gdbarch = spu_gdbarch (SPUADDR_SPU (addr));
+  else
+    current_gdbarch = target_gdbarch;
+  ret = ops_beneath->to_insert_breakpoint (bp);
+  do_cleanups (old_chain);
+
+  return ret;
+}
+
+/* Override the to_remove_breakpoint routine.  */
+static int
+spu_remove_breakpoint (struct bp_target_info *bp)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+  CORE_ADDR addr = bp->placed_address;
+  struct cleanup *old_chain;
+  int ret;
+
+  while (ops_beneath && !ops_beneath->to_remove_breakpoint)
+    ops_beneath = find_target_beneath (ops_beneath);
+  gdb_assert (ops_beneath);
+
+  /* Ignore attempts to remove breakpoints in a stand-alone SPE
+     executable just after startup, before we know the FD.  */
+  if (spu_standalone_p () && addr < SPU_LS_SIZE)
+    return -1;
+
+  old_chain = save_current_gdbarch ();
+  if (SPUADDR_SPU (addr) != -1)
+    current_gdbarch = spu_gdbarch (SPUADDR_SPU (addr));
+  else
+    current_gdbarch = target_gdbarch;
+  ret = ops_beneath->to_remove_breakpoint (bp);
+  do_cleanups (old_chain);
+
+  return ret;
+}
+
+
+/* Override the to_fetch_registers routine.  */
+static void
+spu_fetch_registers (struct regcache *regcache, int regno)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+  int spufs_fd;
+  ULONGEST spufs_addr;
+
+  /* This version applies only if we're currently in spu_run.  */
+  if (gdbarch_bfd_arch_info (get_regcache_arch (regcache))->arch
+      != bfd_arch_spu)
+    {
+      while (ops_beneath && !ops_beneath->to_fetch_registers)
+	ops_beneath = find_target_beneath (ops_beneath);
+
+      gdb_assert (ops_beneath);
+      ops_beneath->to_fetch_registers (regcache, regno);
+      return;
+    }
+
+  /* We must be stopped on a spu_run system call.  */
+  if (!parse_spufs_run (inferior_ptid, &spufs_fd, &spufs_addr))
+    return;
+
+  /* The ID register holds the spufs file handle.  */
+  if (regno == -1 || regno == SPU_ID_REGNUM)
+    {
+      char buf[4];
+      store_unsigned_integer (buf, 4, spufs_fd);
+      regcache_raw_supply (regcache, SPU_ID_REGNUM, buf);
+    }
+
+  /* The NPC register is found in PPC memory at SPUFS_ADDR.  */
+  if (regno == -1 || regno == SPU_PC_REGNUM)
+    {
+      struct cleanup *old_chain;
+      LONGEST ret;
+      char buf[4];
+
+      /* Switch to PPC arch while accessing target memory.  */
+      old_chain = save_current_gdbarch ();
+      current_gdbarch = target_gdbarch;
+      ret = target_read (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
+			 buf, spufs_addr, sizeof buf);
+      do_cleanups (old_chain);
+
+      if (ret == sizeof buf)
+	regcache_raw_supply (regcache, SPU_PC_REGNUM, buf);
+    }
+
+  /* The GPRs are found in the "regs" spufs file.  */
+  if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
+    {
+      char buf[16 * SPU_NUM_GPRS], annex[32];
+      int i;
+
+      xsnprintf (annex, sizeof annex, "%d/regs", spufs_fd);
+      if (target_read (ops_beneath, TARGET_OBJECT_SPU, annex,
+		       buf, 0, sizeof buf) == sizeof buf)
+	for (i = 0; i < SPU_NUM_GPRS; i++)
+	  regcache_raw_supply (regcache, i, buf + i*16);
+    }
+}
+
+/* Override the to_store_registers routine.  */
+static void
+spu_store_registers (struct regcache *regcache, int regno)
+{
+  struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
+  int spufs_fd;
+  ULONGEST spufs_addr;
+
+  /* This version applies only if we're currently in spu_run.  */
+  if (gdbarch_bfd_arch_info (get_regcache_arch (regcache))->arch
+      != bfd_arch_spu)
+    {
+      while (ops_beneath && !ops_beneath->to_fetch_registers)
+	ops_beneath = find_target_beneath (ops_beneath);
+
+      gdb_assert (ops_beneath);
+      ops_beneath->to_store_registers (regcache, regno);
+      return;
+    }
+
+  /* We must be stopped on a spu_run system call.  */
+  if (!parse_spufs_run (inferior_ptid, &spufs_fd, &spufs_addr))
+    return;
+
+  /* The NPC register is found in PPC memory at SPUFS_ADDR.  */
+  if (regno == -1 || regno == SPU_PC_REGNUM)
+    {
+      struct cleanup *old_chain;
+      char buf[4];
+      regcache_raw_collect (regcache, SPU_PC_REGNUM, buf);
+
+      /* Switch to PPC arch while accessing target memory.  */
+      old_chain = save_current_gdbarch ();
+      current_gdbarch = target_gdbarch;
+      target_write (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
+		    buf, spufs_addr, sizeof buf);
+      do_cleanups (old_chain);
+    }
+
+  /* The GPRs are found in the "regs" spufs file.  */
+  if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
+    {
+      char buf[16 * SPU_NUM_GPRS], annex[32];
+      int i;
+
+      for (i = 0; i < SPU_NUM_GPRS; i++)
+	regcache_raw_collect (regcache, i, buf + i*16);
+
+      xsnprintf (annex, sizeof annex, "%d/regs", spufs_fd);
+      target_write (ops_beneath, TARGET_OBJECT_SPU, annex,
+		    buf, 0, sizeof buf);
+    }
+}
+
+/* Override the to_xfer_partial routine.  */
+static LONGEST
+spu_xfer_partial (struct target_ops *ops, enum target_object object,
+		  const char *annex, gdb_byte *readbuf,
+		  const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  struct target_ops *ops_beneath = find_target_beneath (ops);
+
+  /* Use the "mem" spufs file to access SPU local store.  */
+  if (object == TARGET_OBJECT_MEMORY)
+    {
+      int fd = SPUADDR_SPU (offset);
+      CORE_ADDR addr = SPUADDR_ADDR (offset);
+      char mem_annex[32];
+
+      if (fd >= 0 && addr < SPU_LS_SIZE)
+	{
+	  xsnprintf (mem_annex, sizeof mem_annex, "%d/mem", fd);
+	  return ops_beneath->to_xfer_partial (ops_beneath, TARGET_OBJECT_SPU,
+					       mem_annex, readbuf, writebuf,
+					       addr, len);
+	}
+    }
+
+  return ops_beneath->to_xfer_partial (ops_beneath, object, annex,
+				       readbuf, writebuf, offset, len);
+}
+
+/* Override the to_search_memory routine.  */
+static int
+spu_search_memory (struct target_ops* ops,
+		   CORE_ADDR start_addr, ULONGEST search_space_len,
+		   const gdb_byte *pattern, ULONGEST pattern_len,
+		   CORE_ADDR *found_addrp)
+{
+  struct target_ops *ops_beneath = find_target_beneath (ops);
+  while (ops_beneath && !ops_beneath->to_search_memory)
+    ops_beneath = find_target_beneath (ops_beneath);
+
+  /* For SPU local store, always fall back to the simple method.  Likewise
+     if we do not have any target-specific special implementation.  */
+  if (!ops_beneath || SPUADDR_SPU (start_addr) >= 0)
+    return simple_search_memory (ops,
+				 start_addr, search_space_len,
+				 pattern, pattern_len, found_addrp);
+
+  return ops_beneath->to_search_memory (ops_beneath,
+					start_addr, search_space_len,
+					pattern, pattern_len, found_addrp);
+}
+
+
+/* Push and pop the SPU multi-architecture support target.  */
+
+void
+spu_multiarch_enable (void)
+{
+  /* If GDB was configured without SPU architecture support,
+     we cannot install SPU multi-architecture support either.  */
+  if (spu_gdbarch (-1) == NULL)
+    return;
+
+  push_target (&spu_ops);
+}
+
+void
+spu_multiarch_disable (void)
+{
+  unpush_target (&spu_ops);
+}
+
+static void
+spu_mourn_inferior (void)
+{
+  find_target_beneath (&spu_ops)->to_mourn_inferior ();
+  spu_multiarch_disable ();
+}
+
+
+/* Initialize the SPU multi-architecture support target.  */
+
+static void
+init_spu_ops (void)
+{
+  spu_ops.to_shortname = "spu";
+  spu_ops.to_longname = "SPU multi-architecture support.";
+  spu_ops.to_doc = "SPU multi-architecture support.";
+  spu_ops.to_mourn_inferior = spu_mourn_inferior;
+  spu_ops.to_fetch_registers = spu_fetch_registers;
+  spu_ops.to_store_registers = spu_store_registers;
+  spu_ops.to_xfer_partial = spu_xfer_partial;
+  spu_ops.to_search_memory = spu_search_memory;
+  spu_ops.to_insert_breakpoint = spu_insert_breakpoint;
+  spu_ops.to_remove_breakpoint = spu_remove_breakpoint;
+  spu_ops.to_region_ok_for_hw_watchpoint = spu_region_ok_for_hw_watchpoint;
+  spu_ops.to_wait = spu_wait;
+  spu_ops.to_thread_architecture = spu_thread_architecture;
+  spu_ops.to_stratum = arch_stratum;
+  spu_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_spu_multiarch (void)
+{
+  /* Install ourselves on the target stack.  */
+  init_spu_ops ();
+  add_target (&spu_ops);
+}
+
diff -urNp gdb-orig/gdb/spu-tdep.c gdb-head/gdb/spu-tdep.c
--- gdb-orig/gdb/spu-tdep.c	2008-09-05 17:04:07.000000000 +0200
+++ gdb-head/gdb/spu-tdep.c	2008-09-07 23:22:04.568265821 +0200
@@ -40,14 +40,31 @@
 #include "regcache.h"
 #include "reggroups.h"
 #include "floatformat.h"
+#include "block.h"
 #include "observer.h"
+#include "infcall.h"
 
 #include "spu-tdep.h"
 
 
+/* The list of available "set spu " and "show spu " commands.  */
+static struct cmd_list_element *setspucmdlist = NULL;
+static struct cmd_list_element *showspucmdlist = NULL;
+
+/* Whether to stop for new SPE contexts.  */
+static int spu_stop_on_load_p = 0;
+/* Whether to automatically flush the SW-managed cache.  */
+static int spu_auto_flush_cache_p = 1;
+
+
 /* The tdep structure.  */
 struct gdbarch_tdep
 {
+  /* The spufs ID identifying our address space.  */
+  int id;
+  /* The size of this address space.  */
+  CORE_ADDR lslr;
+
   /* SPU-specific vector type.  */
   struct type *spu_builtin_type_vec128;
 };
@@ -322,33 +339,87 @@ spu_register_reggroup_p (struct gdbarch 
   return default_register_reggroup_p (gdbarch, regnum, group);
 }
 
-/* Address conversion.  */
+
+/* Address handling.  */
+
+static CORE_ADDR
+spu_lslr (int id)
+{
+  gdb_byte buf[16];
+  char annex[32];
+
+  xsnprintf (annex, sizeof annex, "%d/lslr", id);
+  memset (buf, 0, sizeof buf);
+  target_read (&current_target, TARGET_OBJECT_SPU, annex,
+	       buf, 0, sizeof buf);
+
+  return strtoulst (buf, NULL, 16);
+}
+
+static int
+spu_address_class_type_flags (int byte_size, int dwarf2_addr_class)
+{
+  if (dwarf2_addr_class == 1)
+    return TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
+  else
+    return 0;
+}
+
+static const char *
+spu_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags)
+{
+  if (type_flags & TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1)
+    return "__ea";
+  else
+    return NULL;
+}
+
+static int
+spu_address_class_name_to_type_flags (struct gdbarch *gdbarch,
+				      const char *name, int *type_flags_ptr)
+{
+  if (strcmp (name, "__ea") == 0)
+    {
+      *type_flags_ptr = TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
+      return 1;
+    }
+  else
+   return 0;
+}
+
+static void
+spu_address_to_pointer (struct gdbarch *gdbarch,
+			struct type *type, gdb_byte *buf, CORE_ADDR addr)
+{
+  store_unsigned_integer (buf, TYPE_LENGTH (type), SPUADDR_ADDR (addr));
+}
 
 static CORE_ADDR
-spu_pointer_to_address (struct type *type, const gdb_byte *buf)
+spu_pointer_to_address (struct gdbarch *gdbarch,
+			struct type *type, const gdb_byte *buf)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   ULONGEST addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
-  ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size.  */
 
-  if (target_has_registers && target_has_stack && target_has_memory)
-    lslr = get_frame_register_unsigned (get_selected_frame (NULL),
-					SPU_LSLR_REGNUM);
+  /* Do not convert __ea pointers.  */
+  if (TYPE_ADDRESS_CLASS_1 (type))
+    return addr;
 
-  return addr & lslr;
+  return addr? SPUADDR (tdep->id, addr & tdep->lslr) : 0;
 }
 
 static CORE_ADDR
 spu_integer_to_address (struct gdbarch *gdbarch,
 			struct type *type, const gdb_byte *buf)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   ULONGEST addr = unpack_long (type, buf);
-  ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size.  */
 
-  if (target_has_registers && target_has_stack && target_has_memory)
-    lslr = get_frame_register_unsigned (get_selected_frame (NULL),
-					SPU_LSLR_REGNUM);
+  /* Do not convert __ea pointers.  */
+  if (TYPE_ADDRESS_CLASS_1 (type))
+    return addr;
 
-  return addr & lslr;
+  return SPUADDR (tdep->id, addr & tdep->lslr);
 }
 
 
@@ -838,8 +909,11 @@ static struct spu_unwind_cache *
 spu_frame_unwind_cache (struct frame_info *this_frame,
 			void **this_prologue_cache)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct spu_unwind_cache *info;
   struct spu_prologue_data data;
+  CORE_ADDR id = tdep->id;
   gdb_byte buf[16];
 
   if (*this_prologue_cache)
@@ -872,6 +946,7 @@ spu_frame_unwind_cache (struct frame_inf
       /* Determine CFA via unwound CFA_REG plus CFA_OFFSET.  */
       get_frame_register (this_frame, data.cfa_reg, buf);
       cfa = extract_unsigned_integer (buf, 4) + data.cfa_offset;
+      cfa = SPUADDR (id, cfa);
 
       /* Call-saved register slots.  */
       for (i = 0; i < SPU_NUM_GPRS; i++)
@@ -894,7 +969,7 @@ spu_frame_unwind_cache (struct frame_inf
 
       /* Get the backchain.  */
       reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
-      status = safe_read_memory_integer (reg, 4, &backchain);
+      status = safe_read_memory_integer (SPUADDR (id, reg), 4, &backchain);
 
       /* A zero backchain terminates the frame chain.  Also, sanity
          check against the local store size limit.  */
@@ -902,11 +977,11 @@ spu_frame_unwind_cache (struct frame_inf
 	{
 	  /* Assume the link register is saved into its slot.  */
 	  if (backchain + 16 < SPU_LS_SIZE)
-	    info->saved_regs[SPU_LR_REGNUM].addr = backchain + 16;
+	    info->saved_regs[SPU_LR_REGNUM].addr = SPUADDR (id, backchain + 16);
 
           /* Frame bases.  */
-	  info->frame_base = backchain;
-	  info->local_base = reg;
+	  info->frame_base = SPUADDR (id, backchain);
+	  info->local_base = SPUADDR (id, reg);
 	}
     }
 
@@ -915,7 +990,8 @@ spu_frame_unwind_cache (struct frame_inf
     return info;
 
   /* The previous SP is equal to the CFA.  */
-  trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, info->frame_base);
+  trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM,
+			SPUADDR_ADDR (info->frame_base));
 
   /* Read full contents of the unwound link register in order to
      be able to determine the return address.  */
@@ -993,24 +1069,28 @@ static const struct frame_base spu_frame
 static CORE_ADDR
 spu_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
   /* Mask off interrupt enable bit.  */
-  return pc & -4;
+  return SPUADDR (tdep->id, pc & -4);
 }
 
 static CORE_ADDR
 spu_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
+  return SPUADDR (tdep->id, sp);
 }
 
 static CORE_ADDR
 spu_read_pc (struct regcache *regcache)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
   ULONGEST pc;
   regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &pc);
   /* Mask off interrupt enable bit.  */
-  return pc & -4;
+  return SPUADDR (tdep->id, pc & -4);
 }
 
 static void
@@ -1020,9 +1100,111 @@ spu_write_pc (struct regcache *regcache,
   ULONGEST old_pc;
   regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &old_pc);
   regcache_cooked_write_unsigned (regcache, SPU_PC_REGNUM,
-				  (pc & -4) | (old_pc & 3));
+				  (SPUADDR_ADDR (pc) & -4) | (old_pc & 3));
+}
+
+
+/* Cell/B.E. cross-architecture unwinder support.  */
+
+struct spu2ppu_cache
+{
+  struct frame_id frame_id;
+  struct regcache *regcache;
+};
+
+static struct gdbarch *
+spu2ppu_prev_arch (struct frame_info *this_frame, void **this_cache)
+{
+  struct spu2ppu_cache *cache = *this_cache;
+  return get_regcache_arch (cache->regcache);
+}
+
+static void
+spu2ppu_this_id (struct frame_info *this_frame,
+		 void **this_cache, struct frame_id *this_id)
+{
+  struct spu2ppu_cache *cache = *this_cache;
+  *this_id = cache->frame_id;
+}
+
+static struct value *
+spu2ppu_prev_register (struct frame_info *this_frame,
+		       void **this_cache, int regnum)
+{
+  struct spu2ppu_cache *cache = *this_cache;
+  struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
+  gdb_byte *buf;
+
+  buf = alloca (register_size (gdbarch, regnum));
+  regcache_cooked_read (cache->regcache, regnum, buf);
+  return frame_unwind_got_bytes (this_frame, regnum, buf);
+}
+
+static int
+spu2ppu_sniffer (const struct frame_unwind *self,
+		 struct frame_info *this_frame, void **this_prologue_cache)
+{
+  CORE_ADDR base, func, backchain;
+  gdb_byte buf[4];
+
+  if (gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_spu)
+    return 0;
+
+  base = get_frame_sp (this_frame);
+  func = get_frame_pc (this_frame);
+  if (target_read_memory (base, buf, 4))
+    return 0;
+  backchain = extract_unsigned_integer (buf, 4);
+
+  if (!backchain)
+    {
+      struct frame_info *fi;
+
+      struct spu2ppu_cache *cache
+	= FRAME_OBSTACK_CALLOC (1, struct spu2ppu_cache);
+
+      cache->frame_id = frame_id_build (base + 16, func);
+
+      for (fi = get_next_frame (this_frame); fi; fi = get_next_frame (fi))
+	if (gdbarch_bfd_arch_info (get_frame_arch (fi))->arch != bfd_arch_spu)
+	  break;
+
+      if (fi)
+	{
+	  cache->regcache = frame_save_as_regcache (fi);
+	  *this_prologue_cache = cache;
+	  return 1;
+	}
+      else
+	{
+	  struct regcache *regcache;
+	  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
+	  cache->regcache = regcache_dup (regcache);
+	  *this_prologue_cache = cache;
+	  return 1;
+	}
+    }
+
+  return 0;
 }
 
+static void
+spu2ppu_dealloc_cache (struct frame_info *self, void *this_cache)
+{
+  struct spu2ppu_cache *cache = this_cache;
+  regcache_xfree (cache->regcache);
+}
+
+static const struct frame_unwind spu2ppu_unwind = {
+  ARCH_FRAME,
+  spu2ppu_this_id,
+  spu2ppu_prev_register,
+  NULL,
+  spu2ppu_sniffer,
+  spu2ppu_dealloc_cache,
+  spu2ppu_prev_arch,
+};
+
 
 /* Function calling convention.  */
 
@@ -1131,7 +1313,7 @@ spu_push_dummy_call (struct gdbarch *gdb
 
   /* Set the return address.  */
   memset (buf, 0, sizeof buf);
-  store_unsigned_integer (buf, 4, bp_addr);
+  store_unsigned_integer (buf, 4, SPUADDR_ADDR (bp_addr));
   regcache_cooked_write (regcache, SPU_LR_REGNUM, buf);
 
   /* If STRUCT_RETURN is true, then the struct return address (in
@@ -1140,7 +1322,7 @@ spu_push_dummy_call (struct gdbarch *gdb
   if (struct_return)
     {
       memset (buf, 0, sizeof buf);
-      store_unsigned_integer (buf, 4, struct_addr);
+      store_unsigned_integer (buf, 4, SPUADDR_ADDR (struct_addr));
       regcache_cooked_write (regcache, regnum++, buf);
     }
 
@@ -1218,9 +1400,10 @@ spu_push_dummy_call (struct gdbarch *gdb
 static struct frame_id
 spu_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   CORE_ADDR pc = get_frame_register_unsigned (this_frame, SPU_PC_REGNUM);
   CORE_ADDR sp = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
-  return frame_id_build (sp, pc & -4);
+  return frame_id_build (SPUADDR (tdep->id, sp), SPUADDR (tdep->id, pc & -4));
 }
 
 /* Function return value access.  */
@@ -1300,18 +1483,18 @@ spu_software_single_step (struct frame_i
      instruction is a PPE-assisted call, in which case it is at PC + 8.
      Wrap around LS limit to be on the safe side.  */
   if ((insn & 0xffffff00) == 0x00002100)
-    next_pc = (pc + 8) & (SPU_LS_SIZE - 1);
+    next_pc = (SPUADDR_ADDR (pc) + 8) & (SPU_LS_SIZE - 1);
   else
-    next_pc = (pc + 4) & (SPU_LS_SIZE - 1);
+    next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1);
 
-  insert_single_step_breakpoint (next_pc);
+  insert_single_step_breakpoint (SPUADDR (SPUADDR_SPU (pc), next_pc));
 
   if (is_branch (insn, &offset, &reg))
     {
       CORE_ADDR target = offset;
 
       if (reg == SPU_PC_REGNUM)
-	target += pc;
+	target += SPUADDR_ADDR (pc);
       else if (reg != -1)
 	{
 	  get_frame_register_bytes (frame, reg, 0, 4, buf);
@@ -1320,12 +1503,35 @@ spu_software_single_step (struct frame_i
 
       target = target & (SPU_LS_SIZE - 1);
       if (target != next_pc)
-	insert_single_step_breakpoint (target);
+	insert_single_step_breakpoint (SPUADDR (SPUADDR_SPU (pc), target));
     }
 
   return 1;
 }
 
+
+/* Disassembler.  */
+
+static void
+spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+{
+  int id = *(int *)info->application_data;
+  CORE_ADDR spu_addr = SPUADDR (id, addr);
+  print_address (spu_addr, info->stream);
+}
+
+static int
+gdb_print_insn_spu (bfd_vma memaddr, disassemble_info * info)
+{
+  /* The opcodes disassembler does 18-bit address arithmetic.  Make sure the
+     SPU ID encoded in the high bits is added back when we call print_address.  */
+  int id = SPUADDR_SPU (memaddr);
+  info->application_data = &id;
+  info->print_address_func = spu_dis_asm_print_address;
+  return print_insn_spu (memaddr, info);
+}
+
+
 /* Target overlays for the SPU overlay manager.
 
    See the documentation of simple_overlay_update for how the
@@ -1442,7 +1648,7 @@ static void
 spu_overlay_update_osect (struct obj_section *osect)
 {
   struct spu_overlay_table *ovly_table;
-  CORE_ADDR val;
+  CORE_ADDR id, val;
 
   ovly_table = spu_get_overlay_table (osect->objfile);
   if (!ovly_table)
@@ -1452,7 +1658,8 @@ spu_overlay_update_osect (struct obj_sec
   if (ovly_table->mapped_ptr == 0)
     return;
 
-  val = read_memory_unsigned_integer (ovly_table->mapped_ptr, 4);
+  id = SPUADDR_SPU (obj_section_addr (osect));
+  val = read_memory_unsigned_integer (SPUADDR (id, ovly_table->mapped_ptr), 4);
   osect->ovly_mapped = (val == ovly_table->mapped_val);
 }
 
@@ -1514,6 +1721,131 @@ spu_overlay_new_objfile (struct objfile 
 }
 
 
+/* Insert temporary breakpoint on "main" function of newly loaded
+   SPE context OBJFILE.  */
+static void
+spu_catch_start (struct objfile *objfile)
+{
+  struct minimal_symbol *minsym;
+  struct symtab *symtab;
+  CORE_ADDR pc;
+  char buf[32];
+
+  /* Do this only if requested by "set spu stop-on-load on".  */
+  if (!spu_stop_on_load_p)
+    return;
+
+  /* Consider only SPU objfiles.  */
+  if (!objfile || bfd_get_arch (objfile->obfd) != bfd_arch_spu)
+    return;
+
+  /* The main objfile is handled differently.  */
+  if (objfile == symfile_objfile)
+    return;
+
+  /* There can be multiple symbols named "main".  Search for the
+     "main" in *this* objfile.  */
+  minsym = lookup_minimal_symbol ("main", NULL, objfile);
+  if (!minsym)
+    return;
+
+  /* If we have debugging information, try to use it -- this
+     will allow us to properly skip the prologue.  */
+  pc = SYMBOL_VALUE_ADDRESS (minsym);
+  symtab = find_pc_sect_symtab (pc, SYMBOL_OBJ_SECTION (minsym));
+  if (symtab != NULL)
+    {
+      struct blockvector *bv = BLOCKVECTOR (symtab);
+      struct block *block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+      struct symbol *sym;
+      struct symtab_and_line sal;
+
+      sym = lookup_block_symbol (block, "main", NULL, VAR_DOMAIN);
+      if (sym)
+	{
+	  fixup_symbol_section (sym, objfile);
+	  sal = find_function_start_sal (sym, 1);
+	  pc = sal.pc;
+	}
+    }
+
+  /* Use a numerical address for the tbreak command to avoid having
+     the breakpoint re-set incorrectly.  */
+  xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
+  tbreak_command (buf, 0);
+}
+
+/* Lookup OBJFILE corresponding to the current SPU context.  */
+static struct objfile *
+spu_objfile_from_context (void)
+{
+  struct frame_info *frame = get_current_frame ();
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct objfile *obj;
+
+  if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu)
+    return NULL;
+
+  ALL_OBJFILES (obj)
+    {
+      if (obj->sections != obj->sections_end
+	  && SPUADDR_SPU (obj_section_addr (obj->sections)) == tdep->id)
+	return obj;
+    }
+
+  return NULL;
+}
+
+/* Flush cache for ea pointer access if available and return 1.  Return 0 if
+   inferior call was not executed.  */
+static void
+flush_ea_cache (void)
+{
+  struct value *ea_flush_fn = NULL;
+  struct minimal_symbol *msymbol;
+  struct objfile *obj;
+
+  obj = spu_objfile_from_context ();
+  if (obj == NULL)
+    return;
+
+  /* Lookup inferior function __cache_flush.  */
+  msymbol = lookup_minimal_symbol ("__cache_flush", NULL, obj);
+  if (msymbol != NULL)
+    {
+      struct type *type;
+      CORE_ADDR addr;
+
+      type = builtin_type_void;
+      type = lookup_function_type (type);
+      type = lookup_pointer_type (type);
+      addr = SYMBOL_VALUE_ADDRESS (msymbol);
+      ea_flush_fn = value_from_pointer (type, addr);
+    }
+
+  if (ea_flush_fn)
+    call_function_by_hand (ea_flush_fn, 0, NULL);
+}
+
+/* This handler is called when the inferior has stopped.  If it is stopped in
+   SPU architecture then flush the ea cache if used.  */
+static void
+spu_attach_normal_stop (struct bpstats *bs)
+{
+  if (!spu_auto_flush_cache_p)
+    return;
+
+  if (!target_has_registers || !target_has_stack || !target_has_memory)
+    return;
+
+  /* Temporarily reset the spu_auto_flush_cache_p to avoid recursively
+     re-entering this function when __cache_flush stops.  */
+  spu_auto_flush_cache_p = 0;
+  flush_ea_cache ();
+  spu_auto_flush_cache_p = 1;
+}
+
 /* "info spu" commands.  */
 
 static void
@@ -2063,6 +2395,37 @@ info_spu_command (char *args, int from_t
 }
 
 
+/* Root of all "set spu "/"show spu " commands.  */
+
+static void
+show_spu_command (char *args, int from_tty)
+{
+  help_list (showspucmdlist, "show spu ", all_commands, gdb_stdout);
+}
+
+static void
+set_spu_command (char *args, int from_tty)
+{
+  help_list (setspucmdlist, "set spu ", all_commands, gdb_stdout);
+}
+
+static void
+show_spu_stop_on_load (struct ui_file *file, int from_tty,
+                       struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Stopping for new SPE threads is %s.\n"),
+                    value);
+}
+
+static void
+show_spu_auto_flush_cache (struct ui_file *file, int from_tty,
+			   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Automatic software-cache flush is %s.\n"),
+                    value);
+}
+
+
 /* Set up gdbarch struct.  */
 
 static struct gdbarch *
@@ -2070,22 +2433,30 @@ spu_gdbarch_init (struct gdbarch_info in
 {
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
+  int id = -1;
 
-  /* Find a candidate among the list of pre-declared architectures.  */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+  /* Which spufs ID was requested as address space?  */
+  if (info.tdep_info)
+    id = *(int *)info.tdep_info;
 
-  /* Is is for us?  */
-  if (info.bfd_arch_info->mach != bfd_mach_spu)
-    return NULL;
+  /* Find a candidate among extant architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      tdep = gdbarch_tdep (arches->gdbarch);
+      if (tdep && tdep->id == id)
+	return arches->gdbarch;
+    }
 
-  /* Yes, create a new architecture.  */
+  /* None found, so create a new architecture.  */
   tdep = XCALLOC (1, struct gdbarch_tdep);
+  tdep->id = id;
+  tdep->lslr = id != -1? spu_lslr (id) : SPU_LS_SIZE - 1;
   gdbarch = gdbarch_alloc (&info, tdep);
 
   /* Disassembler.  */
-  set_gdbarch_print_insn (gdbarch, print_insn_spu);
+  set_gdbarch_print_insn (gdbarch, gdb_print_insn_spu);
 
   /* Registers.  */
   set_gdbarch_num_regs (gdbarch, SPU_NUM_REGS);
@@ -2116,9 +2487,16 @@ spu_gdbarch_init (struct gdbarch_info in
   set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
   set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
 
-  /* Address conversion.  */
+  /* Address handling.  */
+  set_gdbarch_address_to_pointer (gdbarch, spu_address_to_pointer);
   set_gdbarch_pointer_to_address (gdbarch, spu_pointer_to_address);
   set_gdbarch_integer_to_address (gdbarch, spu_integer_to_address);
+  set_gdbarch_address_class_type_flags (gdbarch, spu_address_class_type_flags);
+  set_gdbarch_address_class_type_flags_to_name
+    (gdbarch, spu_address_class_type_flags_to_name);
+  set_gdbarch_address_class_name_to_type_flags
+    (gdbarch, spu_address_class_name_to_type_flags);
+
 
   /* Inferior function calls.  */
   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
@@ -2140,6 +2518,9 @@ spu_gdbarch_init (struct gdbarch_info in
   set_gdbarch_skip_prologue (gdbarch, spu_skip_prologue);
   set_gdbarch_in_function_epilogue_p (gdbarch, spu_in_function_epilogue_p);
 
+  /* Cell/B.E. cross-architecture unwinder support.  */
+  frame_unwind_prepend_unwinder (gdbarch, &spu2ppu_unwind);
+
   /* Breakpoints.  */
   set_gdbarch_decr_pc_after_break (gdbarch, 4);
   set_gdbarch_breakpoint_from_pc (gdbarch, spu_breakpoint_from_pc);
@@ -2161,6 +2542,48 @@ _initialize_spu_tdep (void)
   observer_attach_new_objfile (spu_overlay_new_objfile);
   spu_overlay_data = register_objfile_data ();
 
+  /* Install spu stop-on-load handler.  */
+  observer_attach_new_objfile (spu_catch_start);
+
+  /* Add ourselves to normal_stop event chain.  */
+  observer_attach_normal_stop (spu_attach_normal_stop);
+
+  /* Add root prefix command for all "set spu"/"show spu" commands.  */
+  add_prefix_cmd ("spu", no_class, set_spu_command,
+		  _("Various SPU specific commands."),
+		  &setspucmdlist, "set spu ", 0, &setlist);
+  add_prefix_cmd ("spu", no_class, show_spu_command,
+		  _("Various SPU specific commands."),
+		  &showspucmdlist, "show spu ", 0, &showlist);
+
+  /* Toggle whether or not to add a temporary breakpoint at the "main"
+     function of new SPE contexts.  */
+  add_setshow_boolean_cmd ("stop-on-load", class_support,
+                          &spu_stop_on_load_p, _("\
+Set whether to stop for new SPE threads."),
+                           _("\
+Show whether to stop for new SPE threads."),
+                           _("\
+Use \"on\" to give control to the user when a new SPE threads enters its \"main\" function.\n\
+Use \"off\" to disable stopping for new SPE threads."),
+                          NULL,
+                          show_spu_stop_on_load,
+                          &setspucmdlist, &showspucmdlist);
+
+  /* Toggle whether or not to automatically flush the software-managed
+     cache whenever SPE execution stops.  */
+  add_setshow_boolean_cmd ("auto-flush-cache", class_support,
+                          &spu_auto_flush_cache_p, _("\
+Set whether to automatically flush SW-managed cache."),
+                           _("\
+Show whether to automatically flush SW-managed cache."),
+                           _("\
+Use \"on\" to automatically flush the software-managed cache whenever SPE execution stops.\n\
+Use \"off\" to never automatically flush the software-managed cache."),
+                          NULL,
+                          show_spu_auto_flush_cache,
+                          &setspucmdlist, &showspucmdlist);
+
   /* Add root prefix command for all "info spu" commands.  */
   add_prefix_cmd ("spu", class_info, info_spu_command,
 		  _("Various SPU specific commands."),
diff -urNp gdb-orig/gdb/spu-tdep.h gdb-head/gdb/spu-tdep.h
--- gdb-orig/gdb/spu-tdep.h	2008-01-01 23:53:13.000000000 +0100
+++ gdb-head/gdb/spu-tdep.h	2008-09-07 23:22:00.534180446 +0200
@@ -50,4 +50,17 @@ enum spu_regnum
 /* Local store.  */
 #define SPU_LS_SIZE          0x40000
 
+/* Address conversions.  */
+#define SPUADDR(spu, addr) \
+  ((spu) != -1? (ULONGEST)1 << 63 | (ULONGEST)(spu) << 32 | (addr) : (addr))
+#define SPUADDR_SPU(addr) \
+  (((addr) & (ULONGEST)1 << 63)? (ULONGEST)(addr) >> 32 & 0x7fffffff : -1)
+#define SPUADDR_ADDR(addr) \
+  (((addr) & (ULONGEST)1 << 63)? (ULONGEST)(addr) & 0xffffffff : (addr))
+
+/* SPU multi-architecture support.  */
+extern void set_spu_solib_ops (struct gdbarch *gdbarch);
+extern void spu_multiarch_enable (void);
+extern void spu_multiarch_disable (void);
+
 #endif
diff -urNp gdb-orig/gdb/stack.c gdb-head/gdb/stack.c
--- gdb-orig/gdb/stack.c	2008-09-02 23:19:50.000000000 +0200
+++ gdb-head/gdb/stack.c	2008-09-07 23:21:53.383143971 +0200
@@ -45,6 +45,7 @@
 #include "valprint.h"
 #include "gdbthread.h"
 #include "cp-support.h"
+#include "arch-utils.h"
 
 #include "gdb_assert.h"
 #include <ctype.h>
@@ -109,6 +110,8 @@ print_stack_frame (struct frame_info *fr
 		   enum print_what print_what)
 {
   struct print_stack_frame_args args;
+  struct cleanup *old_chain = save_current_gdbarch ();
+  current_gdbarch = get_frame_arch (frame);
 
   args.frame = frame;
   args.print_level = print_level;
@@ -118,6 +121,7 @@ print_stack_frame (struct frame_info *fr
   args.print_args = 1;
 
   catch_errors (print_stack_frame_stub, &args, "", RETURN_MASK_ERROR);
+  do_cleanups (old_chain);
 }  
 
 struct print_args_args
@@ -223,6 +227,9 @@ print_frame_args (struct symbol *func, s
   stb = ui_out_stream_new (uiout);
   old_chain = make_cleanup_ui_out_stream_delete (stb);
 
+  save_current_gdbarch ();
+  current_gdbarch = get_frame_arch (frame);
+
   if (func)
     {
       struct block *b = SYMBOL_BLOCK_VALUE (func);
@@ -471,9 +478,11 @@ print_frame_info (struct frame_info *fra
   struct symtab_and_line sal;
   int source_print;
   int location_print;
+  struct cleanup *old_chain;
 
   if (get_frame_type (frame) == DUMMY_FRAME
-      || get_frame_type (frame) == SIGTRAMP_FRAME)
+      || get_frame_type (frame) == SIGTRAMP_FRAME
+      || get_frame_type (frame) == ARCH_FRAME)
     {
       struct cleanup *uiout_cleanup
 	= make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
@@ -506,6 +515,10 @@ print_frame_info (struct frame_info *fra
 	  annotate_signal_handler_caller ();
           ui_out_field_string (uiout, "func", "<signal handler called>");
         }
+      else if (get_frame_type (frame) == ARCH_FRAME)
+        {
+          ui_out_field_string (uiout, "func", "<cross-architecture call>");
+	}
       ui_out_text (uiout, "\n");
       annotate_frame_end ();
 
@@ -519,6 +532,10 @@ print_frame_info (struct frame_info *fra
      the next frame is a SIGTRAMP_FRAME or a DUMMY_FRAME, then the
      next frame was not entered as the result of a call, and we want
      to get the line containing FRAME->pc.  */
+
+  old_chain = save_current_gdbarch ();
+  current_gdbarch = get_frame_arch (frame);
+
   find_frame_sal (frame, &sal);
 
   location_print = (print_what == LOCATION 
@@ -572,6 +589,7 @@ print_frame_info (struct frame_info *fra
   annotate_frame_end ();
 
   gdb_flush (gdb_stdout);
+  do_cleanups (old_chain);
 }
 
 static void
@@ -1431,6 +1449,7 @@ static void
 print_frame_local_vars (struct frame_info *frame, int num_tabs,
 			struct ui_file *stream)
 {
+  struct cleanup *old_chain;
   struct block *block = get_frame_block (frame, 0);
   int values_printed = 0;
 
@@ -1440,6 +1459,9 @@ print_frame_local_vars (struct frame_inf
       return;
     }
 
+  old_chain = save_current_gdbarch ();
+  current_gdbarch = get_frame_arch (frame);
+
   while (block)
     {
       if (print_block_frame_locals (block, frame, num_tabs, stream))
@@ -1453,6 +1475,8 @@ print_frame_local_vars (struct frame_inf
 
   if (!values_printed)
     fprintf_filtered (stream, _("No locals.\n"));
+
+  do_cleanups (old_chain);
 }
 
 /* Same, but print labels.  */
diff -urNp gdb-orig/gdb/target.c gdb-head/gdb/target.c
--- gdb-orig/gdb/target.c	2008-09-05 14:02:58.000000000 +0200
+++ gdb-head/gdb/target.c	2008-09-07 23:22:00.544179011 +0200
@@ -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
 
@@ -2025,7 +2031,8 @@ target_require_runnable (void)
       /* Do not worry about thread_stratum targets that can not
 	 create inferiors.  Assume they will be pushed again if
 	 necessary, and continue to the process_stratum.  */
-      if (t->to_stratum == thread_stratum)
+      if (t->to_stratum == thread_stratum
+	  || t->to_stratum == arch_stratum)
 	continue;
 
       error (_("\
@@ -2164,6 +2171,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 +3049,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 +3147,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;
 }
 
 
diff -urNp gdb-orig/gdb/target-descriptions.c gdb-head/gdb/target-descriptions.c
--- gdb-orig/gdb/target-descriptions.c	2008-09-02 23:19:50.000000000 +0200
+++ gdb-head/gdb/target-descriptions.c	2008-09-07 23:21:58.991136448 +0200
@@ -104,6 +104,10 @@ typedef struct tdesc_feature
 } *tdesc_feature_p;
 DEF_VEC_P(tdesc_feature_p);
 
+/* A compatible architecture from a target description.  */
+typedef const struct bfd_arch_info *arch_p;
+DEF_VEC_P(arch_p);
+
 /* A target description.  */
 
 struct target_desc
@@ -111,6 +115,9 @@ struct target_desc
   /* The architecture reported by the target, if any.  */
   const struct bfd_arch_info *arch;
 
+  /* The list of compatible architectures reported by the target.  */
+  VEC(arch_p) *compatible;
+
   /* Any architecture-specific properties specified by the target.  */
   VEC(property_s) *properties;
 
@@ -290,6 +297,28 @@ tdesc_architecture (const struct target_
 {
   return target_desc->arch;
 }
+
+/* Return non-zero if this target description is compatible
+   with the given BFD architecture.  */
+
+int
+tdesc_compatible_p (const struct target_desc *target_desc,
+		    const struct bfd_arch_info *arch)
+{
+  const struct bfd_arch_info *compat;
+  int ix;
+
+  for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat);
+       ix++)
+    {
+      if (compat == arch
+	  || arch->compatible (arch, compat)
+	  || compat->compatible (compat, arch))
+	return 1;
+    }
+
+  return 0;
+}
 
 
 /* Return 1 if this target description includes any registers.  */
@@ -885,6 +914,8 @@ free_target_description (void *arg)
     }
   VEC_free (property_s, target_desc->properties);
 
+  VEC_free (arch_p, target_desc->compatible);
+
   xfree (target_desc);
 }
 
@@ -895,6 +926,30 @@ make_cleanup_free_target_description (st
 }
 
 void
+tdesc_add_compatible (struct target_desc *target_desc,
+		      const struct bfd_arch_info *compatible)
+{
+  const struct bfd_arch_info *compat;
+  int ix;
+
+  /* If this instance of GDB is compiled without BFD support for the
+     compatible architecture, simply ignore it -- we would not be able
+     to handle it anyway.  */
+  if (compatible == NULL)
+    return;
+
+  for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat);
+       ix++)
+    if (compat == compatible)
+      internal_error (__FILE__, __LINE__,
+		      _("Attempted to add duplicate "
+			"compatible architecture \"%s\""),
+		      compatible->printable_name);
+
+  VEC_safe_push (arch_p, target_desc->compatible, compatible);
+}
+
+void
 set_tdesc_property (struct target_desc *target_desc,
 		    const char *key, const char *value)
 {
@@ -993,6 +1048,7 @@ static void
 maint_print_c_tdesc_cmd (char *args, int from_tty)
 {
   const struct target_desc *tdesc;
+  const struct bfd_arch_info *compatible;
   const char *filename, *inp;
   char *function, *outp;
   struct property *prop;
@@ -1049,6 +1105,16 @@ maint_print_c_tdesc_cmd (char *args, int
       printf_unfiltered ("\n");
     }
 
+  for (ix = 0; VEC_iterate (arch_p, tdesc->compatible, ix, compatible);
+       ix++)
+    {
+      printf_unfiltered
+	("  tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n",
+	 compatible->printable_name);
+    }
+  if (ix)
+    printf_unfiltered ("\n");
+
   for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop);
        ix++)
     {
diff -urNp gdb-orig/gdb/target-descriptions.h gdb-head/gdb/target-descriptions.h
--- gdb-orig/gdb/target-descriptions.h	2008-01-01 23:53:13.000000000 +0100
+++ gdb-head/gdb/target-descriptions.h	2008-09-07 23:21:58.995135874 +0200
@@ -123,6 +123,12 @@ int tdesc_numbered_register_choices (con
 const struct bfd_arch_info *tdesc_architecture
   (const struct target_desc *);
 
+/* Return non-zero if this target description is compatible
+   with the given BFD architecture.  */
+
+int tdesc_compatible_p (const struct target_desc *,
+			const struct bfd_arch_info *);
+
 /* Return the string value of a property named KEY, or NULL if the
    property was not specified.  */
 
@@ -169,6 +175,8 @@ void set_tdesc_architecture (struct targ
 			     const struct bfd_arch_info *);
 void set_tdesc_property (struct target_desc *,
 			 const char *key, const char *value);
+void tdesc_add_compatible (struct target_desc *,
+			   const struct bfd_arch_info *);
 
 struct tdesc_feature *tdesc_create_feature (struct target_desc *tdesc,
 					    const char *name);
diff -urNp gdb-orig/gdb/target.h gdb-head/gdb/target.h
--- gdb-orig/gdb/target.h	2008-08-21 21:44:33.000000000 +0200
+++ gdb-head/gdb/target.h	2008-09-07 23:22:00.552177862 +0200
@@ -62,7 +62,8 @@ enum strata
     file_stratum,		/* Executable files, etc */
     core_stratum,		/* Core dump files */
     process_stratum,		/* Executing processes */
-    thread_stratum		/* Executing threads */
+    thread_stratum,		/* Executing threads */
+    arch_stratum		/* Architecture overrides */
   };
 
 enum thread_control_capabilities
@@ -523,6 +524,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 +1029,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'
diff -urNp gdb-orig/gdb/testsuite/gdb.base/dump.exp gdb-head/gdb/testsuite/gdb.base/dump.exp
--- gdb-orig/gdb/testsuite/gdb.base/dump.exp	2008-08-08 16:42:43.000000000 +0200
+++ gdb-head/gdb/testsuite/gdb.base/dump.exp	2008-09-07 23:21:56.875173693 +0200
@@ -42,6 +42,12 @@ if {[istarget "ia64*-*-*"] || [istarget 
     set is64bitonly "yes"
 }
 
+if {[istarget "spu*-*-*"]} then {
+    # The internal address format used for the combined Cell/B.E.
+    # debugger required 64-bit.
+    set is64bitonly "yes"
+}
+
 if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ${options}] != "" } {
      untested dump.exp
      return -1
diff -urNp gdb-orig/gdb/testsuite/gdb.xml/tdesc-regs.exp gdb-head/gdb/testsuite/gdb.xml/tdesc-regs.exp
--- gdb-orig/gdb/testsuite/gdb.xml/tdesc-regs.exp	2008-01-01 23:53:22.000000000 +0100
+++ gdb-head/gdb/testsuite/gdb.xml/tdesc-regs.exp	2008-09-07 23:22:00.560176714 +0200
@@ -39,6 +39,16 @@ switch -glob -- [istarget] {
 	set regdir "rs6000/"
 	set core-regs {power-core.xml}
     }
+    "spu*-*-*" {
+	# This may be either the spu-linux-nat target, or the Cell/B.E.
+	# multi-architecture debugger in SPU standalone executable mode.
+	# We do not support XML register sets on SPU in either case.
+	# However, the multi-arch debugger will accept XML registers sets
+	# (on the PowerPC side), hence the test below would fail.
+	# Simply return unconditionally here.
+	unsupported "register tests"
+	return 0
+    }
 }
 
 # If no core registers were specified, assume this target does not
diff -urNp gdb-orig/gdb/thread.c gdb-head/gdb/thread.c
--- gdb-orig/gdb/thread.c	2008-08-21 21:44:33.000000000 +0200
+++ gdb-head/gdb/thread.c	2008-09-07 23:21:51.719116483 +0200
@@ -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
diff -urNp gdb-orig/gdb/utils.c gdb-head/gdb/utils.c
--- gdb-orig/gdb/utils.c	2008-09-05 13:33:42.000000000 +0200
+++ gdb-head/gdb/utils.c	2008-09-07 23:21:56.858176133 +0200
@@ -2859,7 +2859,6 @@ core_addr_to_string_nz (const CORE_ADDR 
 CORE_ADDR
 string_to_core_addr (const char *my_string)
 {
-  int addr_bit = gdbarch_addr_bit (current_gdbarch);
   CORE_ADDR addr = 0;
 
   if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
@@ -2875,17 +2874,6 @@ string_to_core_addr (const char *my_stri
 	  else
 	    error (_("invalid hex \"%s\""), my_string);
 	}
-
-      /* Not very modular, but if the executable format expects
-         addresses to be sign-extended, then do so if the address was
-         specified with only 32 significant bits.  Really this should
-         be determined by the target architecture, not by the object
-         file.  */
-      if (i - 2 == addr_bit / 4
-	  && exec_bfd
-	  && bfd_get_sign_extend_vma (exec_bfd))
-	addr = (addr ^ ((CORE_ADDR) 1 << (addr_bit - 1)))
-	       - ((CORE_ADDR) 1 << (addr_bit - 1));
     }
   else
     {
diff -urNp gdb-orig/gdb/varobj.c gdb-head/gdb/varobj.c
--- gdb-orig/gdb/varobj.c	2008-09-02 23:19:50.000000000 +0200
+++ gdb-head/gdb/varobj.c	2008-09-07 23:21:56.867174842 +0200
@@ -426,6 +426,8 @@ static struct frame_info *
 find_frame_addr_in_frame_chain (CORE_ADDR frame_addr)
 {
   struct frame_info *frame = NULL;
+  CORE_ADDR frame_base;
+  int addr_bit;
 
   if (frame_addr == (CORE_ADDR) 0)
     return NULL;
@@ -435,7 +437,17 @@ find_frame_addr_in_frame_chain (CORE_ADD
       frame = get_prev_frame (frame);
       if (frame == NULL)
 	return NULL;
-      if (get_frame_base_address (frame) == frame_addr)
+
+      /* The CORE_ADDR we get as argument was parsed from a string GDB
+	 output as $fp.  This output got truncated to gdbarch_addr_bit.
+	 Truncate the frame base address in the same manner before
+	 comparing it against our argument.  */
+      frame_base = get_frame_base_address (frame);
+      addr_bit = gdbarch_addr_bit (get_frame_arch (frame));
+      if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+	frame_base &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+      if (frame_base == frame_addr)
 	return frame;
     }
 }
diff -urNp gdb-orig/gdb/xml-tdesc.c gdb-head/gdb/xml-tdesc.c
--- gdb-orig/gdb/xml-tdesc.c	2008-08-26 14:42:20.000000000 +0200
+++ gdb-head/gdb/xml-tdesc.c	2008-09-07 23:21:59.000135156 +0200
@@ -106,6 +106,20 @@ tdesc_end_arch (struct gdb_xml_parser *p
   set_tdesc_architecture (data->tdesc, arch);
 }
 
+/* Handle the end of a <compatible> element and its value.  */
+
+static void
+tdesc_end_compatible (struct gdb_xml_parser *parser,
+		      const struct gdb_xml_element *element,
+		      void *user_data, const char *body_text)
+{
+  struct tdesc_parsing_data *data = user_data;
+  const struct bfd_arch_info *arch;
+
+  arch = bfd_scan_arch (body_text);
+  tdesc_add_compatible (data->tdesc, arch);
+}
+
 /* Handle the start of a <target> element.  */
 
 static void
@@ -345,6 +359,8 @@ static const struct gdb_xml_attribute ta
 static const struct gdb_xml_element target_children[] = {
   { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
     NULL, tdesc_end_arch },
+  { "compatible", NULL, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    NULL, tdesc_end_compatible },
   { "feature", feature_attributes, feature_children,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_feature, NULL },
diff -urNp gdb-orig/gdb/xstormy16-tdep.c gdb-head/gdb/xstormy16-tdep.c
--- gdb-orig/gdb/xstormy16-tdep.c	2008-08-21 21:44:33.000000000 +0200
+++ gdb-head/gdb/xstormy16-tdep.c	2008-09-07 23:21:57.616200070 +0200
@@ -592,7 +592,8 @@ xstormy16_skip_trampoline_code (struct f
    and vice versa.  */
 
 static CORE_ADDR
-xstormy16_pointer_to_address (struct type *type, const gdb_byte *buf)
+xstormy16_pointer_to_address (struct gdbarch *gdbarch,
+			      struct type *type, const gdb_byte *buf)
 {
   enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
   CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
@@ -608,7 +609,8 @@ xstormy16_pointer_to_address (struct typ
 }
 
 static void
-xstormy16_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
+xstormy16_address_to_pointer (struct gdbarch *gdbarch,
+			      struct type *type, gdb_byte *buf, CORE_ADDR addr)
 {
   enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
 

-- 
  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]