From efcbbd1428e455c9ca59a590a91e4db200b3813c Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 31 Jul 2009 15:25:22 +0000 Subject: [PATCH] ChangeLog: * linux-nat.c: Include . (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 and . (SPUFS_MAGIC): Define. (spu_enumerate_spu_ids): New function. (linux_qxfer_spu): New function. (linux_target_ops): Install linux_qxfer_spu. --- gdb/ChangeLog | 18 ++++ gdb/corelow.c | 77 ++++++++++++++ gdb/gdbserver/ChangeLog | 8 ++ gdb/gdbserver/linux-low.c | 102 +++++++++++++++++- gdb/linux-nat.c | 218 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 422 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 614a76adfeb..832eedc4861 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2009-07-31 Ulrich Weigand + + * linux-nat.c: Include . + (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 * features/Makefile: Allow sub-platform specific expedite settings. diff --git a/gdb/corelow.c b/gdb/corelow.c index 4dbcef06c74..49de82d6352 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -592,6 +592,36 @@ core_files_info (struct target_ops *t) print_section_info (core_data, 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; + 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/". */ + + 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, diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 095e65cb8e0..aaba1d56964 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2009-07-31 Ulrich Weigand + + * linux-low.c: Include and . + (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 * configure.srv (powerpc*-*-linux*): Add powerpc-cell32l.o diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 5edc4730846..a88f4d1f02e 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -40,6 +40,12 @@ #include #include #include +#include +#include + +#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, diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index d91c6be5c22..1308844bf21 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -54,6 +54,11 @@ #include "gdb_dirent.h" #include "xml-support.h" #include "terminal.h" +#include + +#ifndef SPUFS_MAGIC +#define SPUFS_MAGIC 0x23c9b64e +#endif #ifdef HAVE_PERSONALITY # include @@ -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 (¤t_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. -- 2.30.2