ChangeLog:
authorUlrich Weigand <uweigand@de.ibm.com>
Fri, 31 Jul 2009 15:25:22 +0000 (15:25 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Fri, 31 Jul 2009 15:25:22 +0000 (15:25 +0000)
* linux-nat.c: Include <sys/vfs.h>.
(SPUFS_MAGIC): Define.
(spu_enumerate_spu_ids): New function.
(linux_proc_xfer_spu): New function.
(linux_xfer_partial): Handle TARGET_OBJECT_SPU.

(iterate_over_spus): New function.
(struct linux_spu_corefile_data): New data type.
(linux_spu_corefile_callback): New function.
(linux_spu_make_corefile_notes): New function.
(linux_nat_make_corefile_notes): Call it.

* corelow.c (struct spuid_list): New data type.
(add_to_spuid_list): New function.
(core_xfer_partial): Handle TARGET_OBJECT_SPU.

gdbserver/ChangeLog:

* linux-low.c: Include <sys/stat.h> and <sys/vfs.h>.
(SPUFS_MAGIC): Define.
(spu_enumerate_spu_ids): New function.
(linux_qxfer_spu): New function.
(linux_target_ops): Install linux_qxfer_spu.

gdb/ChangeLog
gdb/corelow.c
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/linux-nat.c

index 614a76adfebc0598059579719db70b44d77f49ed..832eedc4861426471516907d18b06706a1131156 100644 (file)
@@ -1,3 +1,21 @@
+2009-07-31  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * linux-nat.c: Include <sys/vfs.h>.
+       (SPUFS_MAGIC): Define.
+       (spu_enumerate_spu_ids): New function.
+       (linux_proc_xfer_spu): New function.
+       (linux_xfer_partial): Handle TARGET_OBJECT_SPU.
+
+       (iterate_over_spus): New function.
+       (struct linux_spu_corefile_data): New data type.
+       (linux_spu_corefile_callback): New function.
+       (linux_spu_make_corefile_notes): New function.
+       (linux_nat_make_corefile_notes): Call it.
+
+       * corelow.c (struct spuid_list): New data type.
+       (add_to_spuid_list): New function.
+       (core_xfer_partial): Handle TARGET_OBJECT_SPU.
+
 2009-07-31  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * features/Makefile: Allow sub-platform specific expedite settings.
index 4dbcef06c7477ce2080ec46886993e2a441945f1..49de82d6352e77478ce958e40de8eda18b9c0859 100644 (file)
@@ -592,6 +592,36 @@ core_files_info (struct target_ops *t)
   print_section_info (core_data, core_bfd);
 }
 \f
+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;
+  enum bfd_endian byte_order
+    = bfd_big_endian (abfd)? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
+  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, byte_order, 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,
@@ -682,6 +712,53 @@ core_xfer_partial (struct target_ops *ops, enum target_object object,
        }
       /* FALL THROUGH */
 
+    case TARGET_OBJECT_SPU:
+      if (readbuf && annex)
+       {
+         /* When the SPU contexts are stored in a 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,
index 095e65cb8e0f15e64daa65be2940493724f71bdb..aaba1d569646e914cc3e2b3d03fceb7804873072 100644 (file)
@@ -1,3 +1,11 @@
+2009-07-31  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * linux-low.c: Include <sys/stat.h> and <sys/vfs.h>.
+       (SPUFS_MAGIC): Define.
+       (spu_enumerate_spu_ids): New function.
+       (linux_qxfer_spu): New function.
+       (linux_target_ops): Install linux_qxfer_spu.
+
 2009-07-31  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * configure.srv (powerpc*-*-linux*): Add powerpc-cell32l.o
index 5edc4730846160261d7e228c5592189935bac80e..a88f4d1f02e8192477898c72082ee034a4d20571 100644 (file)
 #include <pwd.h>
 #include <sys/types.h>
 #include <dirent.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+
+#ifndef SPUFS_MAGIC
+#define SPUFS_MAGIC 0x23c9b64e
+#endif
 
 #ifndef PTRACE_GETSIGINFO
 # define PTRACE_GETSIGINFO 0x4202
@@ -3034,6 +3040,100 @@ linux_supports_multi_process (void)
   return 1;
 }
 
+
+/* 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_qxfer_spu (const char *annex, unsigned char *readbuf,
+                unsigned const char *writebuf,
+                CORE_ADDR offset, int len)
+{
+  long pid = lwpid_of (get_thread_lwp (current_inferior));
+  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 (pid, readbuf, offset, len);
+    }
+
+  sprintf (buf, "/proc/%ld/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
+    ret = read (fd, readbuf, (size_t) len);
+
+  close (fd);
+  return ret;
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
@@ -3064,7 +3164,7 @@ static struct target_ops linux_target_ops = {
 #else
   NULL,
 #endif
-  NULL,
+  linux_qxfer_spu,
   hostio_last_error_from_errno,
   linux_qxfer_osdata,
   linux_xfer_siginfo,
index d91c6be5c222b87559ae44fa335137a2f9086e63..1308844bf214cadc4a3c33dc385c5513b8f788f6 100644 (file)
 #include "gdb_dirent.h"
 #include "xml-support.h"
 #include "terminal.h"
+#include <sys/vfs.h>
+
+#ifndef SPUFS_MAGIC
+#define SPUFS_MAGIC 0x23c9b64e
+#endif
 
 #ifdef HAVE_PERSONALITY
 # include <sys/personality.h>
@@ -3661,6 +3666,119 @@ linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
   return 0;
 }
 
+/* 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.  */
 
@@ -3722,6 +3840,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       xfree (auxv);
     }
 
+  note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
+
   make_cleanup (xfree, note_data);
   return note_data;
 }
@@ -4055,6 +4175,100 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
   return ret;
 }
 
+
+/* Enumerate spufs IDs for process PID.  */
+static LONGEST
+spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, LONGEST len)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  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, byte_order, 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
@@ -4260,6 +4474,10 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
     return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
                                offset, len);
 
+  if (object == TARGET_OBJECT_SPU)
+    return linux_proc_xfer_spu (ops, object, annex, readbuf, writebuf,
+                               offset, len);
+
   /* GDB calculates all the addresses in possibly larget width of the address.
      Address width needs to be masked before its final use - either by
      linux_proc_xfer_partial or inf_ptrace_xfer_partial.