diff options
Diffstat (limited to 'gdb/gdbserver/linux-low.c')
-rw-r--r-- | gdb/gdbserver/linux-low.c | 102 |
1 files changed, 101 insertions, 1 deletions
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 5edc473..a88f4d1 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -40,6 +40,12 @@ #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, |