2011-05-26 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index d102db447623f3dd417d1cee33f3033f02a935c0..e6237422b9b144cef6daa49fdbac9645c1008443 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
    Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #include "osabi.h"
 #include "regset.h"
 #include "solib-svr4.h"
+#include "solib-spu.h"
+#include "solib.h"
+#include "solist.h"
 #include "ppc-tdep.h"
 #include "ppc-linux-tdep.h"
 #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 "xml-syscall.h"
+#include "linux-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-isa205-32l.c"
 #include "features/rs6000/powerpc-isa205-altivec32l.c"
 #include "features/rs6000/powerpc-isa205-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-isa205-64l.c"
 #include "features/rs6000/powerpc-isa205-altivec64l.c"
 #include "features/rs6000/powerpc-isa205-vsx64l.c"
 #include "features/rs6000/powerpc-e500l.c"
 
+/* The syscall's XML filename for PPC and PPC64.  */
+#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
+#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
 
 /* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
    in much the same fashion as memory_remove_breakpoint in mem-break.c,
        Now we've hit the breakpoint at shr1.  (The breakpoint was
        reset from the PLT entry to the actual shr1 function after the
        shared library was loaded.) Note that the PLT entry has been
-       resolved to contain a branch that takes us directly to shr1. 
+       resolved to contain a branch that takes us directly to shr1.
        (The real one, not the PLT entry.)
 
            (gdb) x/2i 0x100409d4
    changed twice.
 
    Now the problem should be obvious.  GDB places a breakpoint (a
-   trap instruction) on the zero value of the PLT entry for shr1. 
+   trap instruction) on the zero value of the PLT entry for shr1.
    Later on, after the shared library had been loaded and the PLT
    initialized, GDB gets a signal indicating this fact and attempts
    (as it always does when it stops) to remove all the breakpoints.
    word) to be written back to the now initialized PLT entry thus
    destroying a portion of the initialization that had occurred only a
    short time ago.  When execution continued, the zero word would be
-   executed as an instruction an an illegal instruction trap was
+   executed as an instruction an illegal instruction trap was
    generated instead.  (0 is not a legal instruction.)
 
    The fix for this problem was fairly straightforward.  The function
    that the latter does not is check to make sure that the breakpoint
    location actually contains a breakpoint (trap instruction) prior
    to attempting to write back the old contents.  If it does contain
-   a trap instruction, we allow the old contents to be written back. 
+   a trap instruction, we allow the old contents to be written back.
    Otherwise, we silently do nothing.
 
    The big question is whether memory_remove_breakpoint () should be
@@ -200,7 +216,7 @@ ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
 
   /* If our breakpoint is no longer at the address, this means that the
      program modified the code on us, so it is wrong to put back the
-     old value */
+     old value */
   if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
     val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
 
@@ -268,8 +284,8 @@ read_insn (CORE_ADDR pc)
 /* An instruction to match.  */
 struct insn_pattern
 {
-  unsigned int mask;            /* mask the insn with this... */
-  unsigned int data;            /* ...and see if it matches this. */
+  unsigned int mask;            /* mask the insn with this...  */
+  unsigned int data;            /* ...and see if it matches this.  */
   int optional;                 /* If non-zero, this insn may be absent.  */
 };
 
@@ -501,25 +517,49 @@ ppc64_standard_linkage1_target (struct frame_info *frame,
 
 static struct core_regset_section ppc_linux_vsx_regset_sections[] =
 {
-  { ".reg", 268 },
-  { ".reg2", 264 },
-  { ".reg-ppc-vmx", 544 },
-  { ".reg-ppc-vsx", 256 },
+  { ".reg", 48 * 4, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
+  { ".reg-ppc-vmx", 544, "ppc Altivec" },
+  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
   { NULL, 0}
 };
 
 static struct core_regset_section ppc_linux_vmx_regset_sections[] =
 {
-  { ".reg", 268 },
-  { ".reg2", 264 },
-  { ".reg-ppc-vmx", 544 },
+  { ".reg", 48 * 4, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
+  { ".reg-ppc-vmx", 544, "ppc Altivec" },
   { NULL, 0}
 };
 
 static struct core_regset_section ppc_linux_fp_regset_sections[] =
 {
-  { ".reg", 268 },
-  { ".reg2", 264 },
+  { ".reg", 48 * 4, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
+  { NULL, 0}
+};
+
+static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
+{
+  { ".reg", 48 * 8, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
+  { ".reg-ppc-vmx", 544, "ppc Altivec" },
+  { ".reg-ppc-vsx", 256, "POWER7 VSX" },
+  { NULL, 0}
+};
+
+static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
+{
+  { ".reg", 48 * 8, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
+  { ".reg-ppc-vmx", 544, "ppc Altivec" },
+  { NULL, 0}
+};
+
+static struct core_regset_section ppc64_linux_fp_regset_sections[] =
+{
+  { ".reg", 48 * 8, "general-purpose" },
+  { ".reg2", 264, "floating-point" },
   { NULL, 0}
 };
 
@@ -872,7 +912,8 @@ ppc_linux_sigtramp_cache (struct frame_info *this_frame,
   for (i = 0; i < 32; i++)
     {
       int regnum = i + tdep->ppc_gp0_regnum;
-      trad_frame_set_reg_addr (this_cache, regnum, gpregs + i * tdep->wordsize);
+      trad_frame_set_reg_addr (this_cache,
+                              regnum, gpregs + i * tdep->wordsize);
     }
   trad_frame_set_reg_addr (this_cache,
                           gdbarch_pc_regnum (gdbarch),
@@ -1001,6 +1042,46 @@ static struct tramp_frame ppc64_linux_sighandler_tramp_frame = {
 };
 
 
+/* 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)
@@ -1015,6 +1096,39 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
          && register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
 }
 
+/* Return the current system call's number present in the
+   r0 register.  When the function fails, it returns -1.  */
+static LONGEST
+ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
+                              ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct cleanup *cleanbuf;
+  /* The content of a register */
+  gdb_byte *buf;
+  /* The result */
+  LONGEST ret;
+
+  /* Make sure we're in a 32- or 64-bit machine */
+  gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8);
+
+  buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
+
+  cleanbuf = make_cleanup (xfree, buf);
+
+  /* Getting the system call number from the register.
+     When dealing with PowerPC architecture, this information
+     is stored at 0th register.  */
+  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf);
+
+  ret = extract_signed_integer (buf, tdep->wordsize, byte_order);
+  do_cleanups (cleanbuf);
+
+  return ret;
+}
+
 static void
 ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
@@ -1034,11 +1148,18 @@ ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
     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");
@@ -1048,7 +1169,9 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
   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;
@@ -1056,7 +1179,9 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
        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;
@@ -1068,6 +1193,300 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
     }
 }
 
+
+/* Cell/B.E. active SPE context tracking support.  */
+
+static struct objfile *spe_context_objfile = NULL;
+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;
+
+/* Hook into inferior_created, solib_loaded, and solib_unloaded observers
+   to track whether we've loaded a version of libspe2 (as static or dynamic
+   library) that provides the __spe_current_active_context variable.  */
+static void
+ppc_linux_spe_context_lookup (struct objfile *objfile)
+{
+  struct minimal_symbol *sym;
+
+  if (!objfile)
+    {
+      spe_context_objfile = NULL;
+      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_objfile = objfile;
+      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;
+    }
+}
+
+static void
+ppc_linux_spe_context_inferior_created (struct target_ops *t, int from_tty)
+{
+  struct objfile *objfile;
+
+  ppc_linux_spe_context_lookup (NULL);
+  ALL_OBJFILES (objfile)
+    ppc_linux_spe_context_lookup (objfile);
+}
+
+static void
+ppc_linux_spe_context_solib_loaded (struct so_list *so)
+{
+  if (strstr (so->so_original_name, "/libspe") != NULL)
+    {
+      solib_read_symbols (so, 0);
+      ppc_linux_spe_context_lookup (so->objfile);
+    }
+}
+
+static void
+ppc_linux_spe_context_solib_unloaded (struct so_list *so)
+{
+  if (so->objfile == spe_context_objfile)
+    ppc_linux_spe_context_lookup (NULL);
+}
+
+/* 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, enum bfd_endian byte_order,
+                      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_objfile)
+    return 0;
+
+  /* Look up cached address of thread-local variable.  */
+  if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
+    {
+      struct target_ops *target = &current_target;
+      volatile struct gdb_exception ex;
+
+      while (target && !target->to_get_thread_local_address)
+       target = find_target_beneath (target);
+      if (!target)
+       return 0;
+
+      TRY_CATCH (ex, RETURN_MASK_ERROR)
+       {
+         /* We do not call target_translate_tls_address here, because
+            svr4_fetch_objfile_link_map may invalidate the frame chain,
+            which must not do while inside a frame sniffer.
+
+            Instead, we have cached the lm_addr value, and use that to
+            directly call the target's to_get_thread_local_address.  */
+         spe_context_cache_address
+           = target->to_get_thread_local_address (target, 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, byte_order);
+
+  /* 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, byte_order);
+    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, byte_order);
+      if (npc)
+       *npc = extract_unsigned_integer (buf + 4, 4, byte_order);
+    }
+
+  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));
+
+  if (regnum < gdbarch_num_regs (gdbarch))
+    regcache_raw_read (cache->regcache, regnum, buf);
+  else
+    gdbarch_pseudo_register_read (gdbarch, cache->regcache, regnum, buf);
+
+  return frame_unwind_got_bytes (this_frame, regnum, buf);
+}
+
+struct ppu2spu_data
+{
+  struct gdbarch *gdbarch;
+  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;
+  enum bfd_endian byte_order = gdbarch_byte_order (data->gdbarch);
+
+  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, byte_order, data->id);
+  else if (regnum == SPU_PC_REGNUM)
+    store_unsigned_integer (buf, 4, byte_order, data->npc);
+  else
+    return REG_UNAVAILABLE;
+
+  return REG_VALID;
+}
+
+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);
+  enum bfd_endian byte_order = gdbarch_byte_order (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, byte_order);
+
+  spe_context = ppc_linux_spe_context (tdep->wordsize, byte_order,
+                                      n, &data.id, &data.npc);
+  if (spe_context && base <= spe_context && spe_context < backchain)
+    {
+      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;
+      data.gdbarch = gdbarch_find_by_info (info);
+      if (!data.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 address_space *aspace = get_frame_address_space (this_frame);
+         struct regcache *regcache = regcache_xmalloc (data.gdbarch, aspace);
+         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,
+  default_frame_unwind_stop_reason,
+  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)
@@ -1075,6 +1494,8 @@ ppc_linux_init_abi (struct gdbarch_info info,
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
 
+  linux_init_abi (info, gdbarch);
+
   /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
      128-bit, they are IBM long double, not IEEE quad long double as
      in the System V ABI PowerPC Processor Supplement.  We can safely
@@ -1086,12 +1507,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
   /* Handle inferior calls during interrupted system calls.  */
   set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
 
+  /* Get the syscall number from the arch's register.  */
+  set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+
   if (tdep->wordsize == 4)
     {
       /* Until November 2001, gcc did not comply with the 32 bit SysV
         R4 ABI requirement that structures less than or equal to 8
         bytes should be returned in registers.  Instead GCC was using
-        the the AIX/PowerOpen ABI - everything returned in memory
+        the AIX/PowerOpen ABI - everything returned in memory
         (well ignoring vectors that is).  When this was corrected, it
         wasn't fixed for GNU/Linux native platform.  Use the
         PowerOpen struct convention.  */
@@ -1105,15 +1529,33 @@ ppc_linux_init_abi (struct gdbarch_info info,
       set_solib_svr4_fetch_link_map_offsets
         (gdbarch, svr4_ilp32_fetch_link_map_offsets);
 
+      /* Setting the correct XML syscall filename.  */
+      set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
+
       /* Trampolines.  */
-      tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
-      tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
+      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");
+
+      /* Supported register sections.  */
+      if (tdesc_find_feature (info.target_desc,
+                             "org.gnu.gdb.power.vsx"))
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc_linux_vsx_regset_sections);
+      else if (tdesc_find_feature (info.target_desc,
+                              "org.gnu.gdb.power.altivec"))
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc_linux_vmx_regset_sections);
+      else
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc_linux_fp_regset_sections);
     }
   
   if (tdep->wordsize == 8)
@@ -1128,28 +1570,37 @@ ppc_linux_init_abi (struct gdbarch_info info,
       set_solib_svr4_fetch_link_map_offsets
         (gdbarch, svr4_lp64_fetch_link_map_offsets);
 
+      /* Setting the correct XML syscall filename.  */
+      set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
+
       /* Trampolines.  */
-      tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
-      tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
+      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);
 
-  /* Supported register sections.  */
-  if (tdesc_find_feature (info.target_desc,
-                         "org.gnu.gdb.power.vsx"))
-    set_gdbarch_core_regset_sections (gdbarch, ppc_linux_vsx_regset_sections);
-  else if (tdesc_find_feature (info.target_desc,
+      /* Supported register sections.  */
+      if (tdesc_find_feature (info.target_desc,
+                             "org.gnu.gdb.power.vsx"))
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc64_linux_vsx_regset_sections);
+      else if (tdesc_find_feature (info.target_desc,
                               "org.gnu.gdb.power.altivec"))
-    set_gdbarch_core_regset_sections (gdbarch, ppc_linux_vmx_regset_sections);
-  else
-    set_gdbarch_core_regset_sections (gdbarch, ppc_linux_fp_regset_sections);
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc64_linux_vmx_regset_sections);
+      else
+       set_gdbarch_core_regset_sections (gdbarch,
+                                         ppc64_linux_fp_regset_sections);
+    }
+  set_gdbarch_regset_from_core_section (gdbarch,
+                                       ppc_linux_regset_from_core_section);
+  set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
@@ -1176,6 +1627,22 @@ ppc_linux_init_abi (struct gdbarch_info 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);
+    }
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -1193,15 +1660,25 @@ _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);
+
+  /* Attach to observers to track __spe_current_active_context.  */
+  observer_attach_inferior_created (ppc_linux_spe_context_inferior_created);
+  observer_attach_solib_loaded (ppc_linux_spe_context_solib_loaded);
+  observer_attach_solib_unloaded (ppc_linux_spe_context_solib_unloaded);
+
   /* Initialize the Linux target descriptions.  */
   initialize_tdesc_powerpc_32l ();
   initialize_tdesc_powerpc_altivec32l ();
+  initialize_tdesc_powerpc_cell32l ();
   initialize_tdesc_powerpc_vsx32l ();
   initialize_tdesc_powerpc_isa205_32l ();
   initialize_tdesc_powerpc_isa205_altivec32l ();
   initialize_tdesc_powerpc_isa205_vsx32l ();
   initialize_tdesc_powerpc_64l ();
   initialize_tdesc_powerpc_altivec64l ();
+  initialize_tdesc_powerpc_cell64l ();
   initialize_tdesc_powerpc_vsx64l ();
   initialize_tdesc_powerpc_isa205_64l ();
   initialize_tdesc_powerpc_isa205_altivec64l ();
This page took 0.031877 seconds and 4 git commands to generate.