aboutsummaryrefslogtreecommitdiff
path: root/gdb/spu-linux-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/spu-linux-nat.c')
-rw-r--r--gdb/spu-linux-nat.c661
1 files changed, 0 insertions, 661 deletions
diff --git a/gdb/spu-linux-nat.c b/gdb/spu-linux-nat.c
deleted file mode 100644
index 635366b..0000000
--- a/gdb/spu-linux-nat.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/* SPU native-dependent code for GDB, the GNU debugger.
- Copyright (C) 2006-2019 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 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include "defs.h"
-#include "gdbcore.h"
-#include "target.h"
-#include "inferior.h"
-#include "inf-child.h"
-#include "inf-ptrace.h"
-#include "regcache.h"
-#include "symfile.h"
-#include "gdbsupport/gdb_wait.h"
-#include "gdbthread.h"
-#include "gdb_bfd.h"
-
-#include "nat/gdb_ptrace.h"
-#include <asm/ptrace.h>
-#include <sys/types.h>
-
-#include "spu-tdep.h"
-
-/* PPU side system calls. */
-#define INSTR_SC 0x44000002
-#define NR_spu_run 0x0116
-
-class spu_linux_nat_target final : public inf_ptrace_target
-{
-public:
- void fetch_registers (struct regcache *regcache, int regnum) override;
- void store_registers (struct regcache *regcache, int regnum) override;
-
- void post_attach (int) override;
- void post_startup_inferior (ptid_t) override;
-
- ptid_t wait (ptid_t, struct target_waitstatus *, int options) override;
-
- enum target_xfer_status xfer_partial (enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len) override;
-
- int can_use_hw_breakpoint (enum bptype, int, int) override;
-};
-
-static spu_linux_nat_target the_spu_linux_nat_target;
-
-/* Fetch PPU register REGNO. */
-static ULONGEST
-fetch_ppc_register (int regno)
-{
- PTRACE_TYPE_RET res;
-
- int tid = inferior_ptid.lwp ();
- if (tid == 0)
- tid = inferior_ptid.pid ();
-
-#ifndef __powerpc64__
- /* If running as a 32-bit process on a 64-bit system, we attempt
- to get the full 64-bit register content of the target process.
- If the PPC special ptrace call fails, we're on a 32-bit system;
- just fall through to the regular ptrace call in that case. */
- {
- gdb_byte buf[8];
-
- errno = 0;
- ptrace (PPC_PTRACE_PEEKUSR_3264, tid,
- (PTRACE_TYPE_ARG3) (regno * 8), buf);
- if (errno == 0)
- ptrace (PPC_PTRACE_PEEKUSR_3264, tid,
- (PTRACE_TYPE_ARG3) (regno * 8 + 4), buf + 4);
- if (errno == 0)
- return (ULONGEST) *(uint64_t *)buf;
- }
-#endif
-
- errno = 0;
- res = ptrace (PT_READ_U, tid,
- (PTRACE_TYPE_ARG3) (regno * sizeof (PTRACE_TYPE_RET)), 0);
- if (errno != 0)
- {
- char mess[128];
- xsnprintf (mess, sizeof mess, "reading PPC register #%d", regno);
- perror_with_name (_(mess));
- }
-
- return (ULONGEST) (unsigned long) res;
-}
-
-/* Fetch WORD from PPU memory at (aligned) MEMADDR in thread TID. */
-static int
-fetch_ppc_memory_1 (int tid, ULONGEST memaddr, PTRACE_TYPE_RET *word)
-{
- errno = 0;
-
-#ifndef __powerpc64__
- if (memaddr >> 32)
- {
- uint64_t addr_8 = (uint64_t) memaddr;
- ptrace (PPC_PTRACE_PEEKTEXT_3264, tid, (PTRACE_TYPE_ARG3) &addr_8, word);
- }
- else
-#endif
- *word = ptrace (PT_READ_I, tid, (PTRACE_TYPE_ARG3) (size_t) memaddr, 0);
-
- return errno;
-}
-
-/* Store WORD into PPU memory at (aligned) MEMADDR in thread TID. */
-static int
-store_ppc_memory_1 (int tid, ULONGEST memaddr, PTRACE_TYPE_RET word)
-{
- errno = 0;
-
-#ifndef __powerpc64__
- if (memaddr >> 32)
- {
- uint64_t addr_8 = (uint64_t) memaddr;
- ptrace (PPC_PTRACE_POKEDATA_3264, tid, (PTRACE_TYPE_ARG3) &addr_8, word);
- }
- else
-#endif
- ptrace (PT_WRITE_D, tid, (PTRACE_TYPE_ARG3) (size_t) memaddr, word);
-
- return errno;
-}
-
-/* Fetch LEN bytes of PPU memory at MEMADDR to MYADDR. */
-static int
-fetch_ppc_memory (ULONGEST memaddr, gdb_byte *myaddr, int len)
-{
- int i, ret;
-
- ULONGEST addr = memaddr & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
- int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
- / sizeof (PTRACE_TYPE_RET));
- PTRACE_TYPE_RET *buffer;
-
- int tid = inferior_ptid.lwp ();
- if (tid == 0)
- tid = inferior_ptid.pid ();
-
- buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
- for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
- {
- ret = fetch_ppc_memory_1 (tid, addr, &buffer[i]);
- if (ret)
- return ret;
- }
-
- memcpy (myaddr,
- (char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
- len);
-
- return 0;
-}
-
-/* Store LEN bytes from MYADDR to PPU memory at MEMADDR. */
-static int
-store_ppc_memory (ULONGEST memaddr, const gdb_byte *myaddr, int len)
-{
- int i, ret;
-
- ULONGEST addr = memaddr & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
- int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
- / sizeof (PTRACE_TYPE_RET));
- PTRACE_TYPE_RET *buffer;
-
- int tid = inferior_ptid.lwp ();
- if (tid == 0)
- tid = inferior_ptid.pid ();
-
- buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
-
- if (addr != memaddr || len < (int) sizeof (PTRACE_TYPE_RET))
- {
- ret = fetch_ppc_memory_1 (tid, addr, &buffer[0]);
- if (ret)
- return ret;
- }
-
- if (count > 1)
- {
- ret = fetch_ppc_memory_1 (tid, addr + (count - 1)
- * sizeof (PTRACE_TYPE_RET),
- &buffer[count - 1]);
- if (ret)
- return ret;
- }
-
- memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
- myaddr, len);
-
- for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
- {
- ret = store_ppc_memory_1 (tid, addr, buffer[i]);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-
-/* 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, ULONGEST *addr)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
- gdb_byte buf[4];
- ULONGEST pc = fetch_ppc_register (32); /* nip */
-
- /* Fetch instruction preceding current NIP. */
- if (fetch_ppc_memory (pc-4, buf, 4) != 0)
- return 0;
- /* It should be a "sc" instruction. */
- if (extract_unsigned_integer (buf, 4, byte_order) != INSTR_SC)
- return 0;
- /* System call number should be NR_spu_run. */
- if (fetch_ppc_register (0) != NR_spu_run)
- return 0;
-
- /* Register 3 contains fd, register 4 the NPC param pointer. */
- *fd = fetch_ppc_register (34); /* orig_gpr3 */
- *addr = fetch_ppc_register (4);
- return 1;
-}
-
-
-/* Implement the to_xfer_partial target_ops method for TARGET_OBJECT_SPU.
- Copy LEN bytes at OFFSET in spufs file ANNEX into/from READBUF or WRITEBUF,
- using the /proc file system. */
-
-static enum target_xfer_status
-spu_proc_xfer_spu (const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
-{
- char buf[128];
- int fd = 0;
- int ret = -1;
- int pid = inferior_ptid.pid ();
-
- if (!annex)
- return TARGET_XFER_EOF;
-
- xsnprintf (buf, sizeof buf, "/proc/%d/fd/%s", pid, annex);
- fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
- if (fd <= 0)
- return TARGET_XFER_E_IO;
-
- if (offset != 0
- && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
- {
- close (fd);
- return TARGET_XFER_EOF;
- }
-
- if (writebuf)
- ret = write (fd, writebuf, (size_t) len);
- else if (readbuf)
- ret = read (fd, readbuf, (size_t) len);
-
- close (fd);
- if (ret < 0)
- return TARGET_XFER_E_IO;
- else if (ret == 0)
- return TARGET_XFER_EOF;
- else
- {
- *xfered_len = (ULONGEST) ret;
- return TARGET_XFER_OK;
- }
-}
-
-
-/* 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 (struct bfd *nbfd, void *open_closure)
-{
- return open_closure;
-}
-
-static int
-spu_bfd_iovec_close (struct bfd *nbfd, void *stream)
-{
- xfree (stream);
-
- /* Zero means success. */
- return 0;
-}
-
-static file_ptr
-spu_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
- file_ptr nbytes, file_ptr offset)
-{
- ULONGEST addr = *(ULONGEST *)stream;
-
- if (fetch_ppc_memory (addr + offset, (gdb_byte *)buf, nbytes) != 0)
- {
- bfd_set_error (bfd_error_invalid_operation);
- return -1;
- }
-
- return nbytes;
-}
-
-static int
-spu_bfd_iovec_stat (struct 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. */
- memset (sb, 0, sizeof (struct stat));
- sb->st_size = INT_MAX;
- return 0;
-}
-
-static gdb_bfd_ref_ptr
-spu_bfd_open (ULONGEST addr)
-{
- asection *spu_name;
-
- ULONGEST *open_closure = XNEW (ULONGEST);
- *open_closure = addr;
-
- gdb_bfd_ref_ptr nbfd (gdb_bfd_openr_iovec ("<in-memory>", "elf32-spu",
- spu_bfd_iovec_open, open_closure,
- spu_bfd_iovec_pread,
- spu_bfd_iovec_close,
- spu_bfd_iovec_stat));
- if (nbfd == NULL)
- return NULL;
-
- if (!bfd_check_format (nbfd.get (), bfd_object))
- return NULL;
-
- /* Retrieve SPU name note and update BFD name. */
- spu_name = bfd_get_section_by_name (nbfd.get (), ".note.spu_name");
- if (spu_name)
- {
- int sect_size = bfd_section_size (spu_name);
- if (sect_size > 20)
- {
- char *buf = (char *)alloca (sect_size - 20 + 1);
- bfd_get_section_contents (nbfd.get (), spu_name, buf, 20,
- sect_size - 20);
- buf[sect_size - 20] = '\0';
-
- bfd_set_filename (nbfd.get (), xstrdup (buf));
- }
- }
-
- return nbfd;
-}
-
-/* INFERIOR_FD is a file handle passed by the inferior to the
- spu_run system call. Assuming the SPE context was allocated
- by the libspe library, try to retrieve the main SPE executable
- file from its copy within the target process. */
-static void
-spu_symbol_file_add_from_memory (int inferior_fd)
-{
- ULONGEST addr;
-
- gdb_byte id[128];
- char annex[32];
- ULONGEST len;
- enum target_xfer_status status;
-
- /* Read object ID. */
- xsnprintf (annex, sizeof annex, "%d/object-id", inferior_fd);
- status = spu_proc_xfer_spu (annex, id, NULL, 0, sizeof id, &len);
- if (status != TARGET_XFER_OK || len >= sizeof id)
- return;
- id[len] = 0;
- addr = strtoulst ((const char *) id, NULL, 16);
- if (!addr)
- return;
-
- /* Open BFD representing SPE executable and read its symbols. */
- gdb_bfd_ref_ptr nbfd (spu_bfd_open (addr));
- if (nbfd != NULL)
- {
- symbol_file_add_from_bfd (nbfd.get (), bfd_get_filename (nbfd),
- SYMFILE_VERBOSE | SYMFILE_MAINLINE,
- NULL, 0, NULL);
- }
-}
-
-
-/* Override the post_startup_inferior routine to continue running
- the inferior until the first spu_run system call. */
-void
-spu_linux_nat_target::post_startup_inferior (ptid_t ptid)
-{
- int fd;
- ULONGEST addr;
-
- int tid = ptid.lwp ();
- if (tid == 0)
- tid = ptid.pid ();
-
- while (!parse_spufs_run (&fd, &addr))
- {
- ptrace (PT_SYSCALL, tid, (PTRACE_TYPE_ARG3) 0, 0);
- waitpid (tid, NULL, __WALL | __WNOTHREAD);
- }
-}
-
-/* Override the post_attach routine to try load the SPE executable
- file image from its copy inside the target process. */
-void
-spu_linux_nat_target::post_attach (int pid)
-{
- int fd;
- ULONGEST addr;
-
- /* Like child_post_startup_inferior, if we happened to attach to
- the inferior while it wasn't currently in spu_run, continue
- running it until we get back there. */
- while (!parse_spufs_run (&fd, &addr))
- {
- ptrace (PT_SYSCALL, pid, (PTRACE_TYPE_ARG3) 0, 0);
- waitpid (pid, NULL, __WALL | __WNOTHREAD);
- }
-
- /* If the user has not provided an executable file, try to extract
- the image from inside the target process. */
- if (!get_exec_file (0))
- spu_symbol_file_add_from_memory (fd);
-}
-
-/* Wait for child PTID to do something. Return id of the child,
- minus_one_ptid in case of error; store status into *OURSTATUS. */
-ptid_t
-spu_linux_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
- int options)
-{
- int save_errno;
- int status;
- pid_t pid;
-
- do
- {
- set_sigint_trap (); /* Causes SIGINT to be passed on to the
- attached process. */
-
- pid = waitpid (ptid.pid (), &status, 0);
- if (pid == -1 && errno == ECHILD)
- /* Try again with __WCLONE to check cloned processes. */
- pid = waitpid (ptid.pid (), &status, __WCLONE);
-
- save_errno = errno;
-
- /* Make sure we don't report an event for the exit of the
- original program, if we've detached from it. */
- if (pid != -1 && !WIFSTOPPED (status)
- && pid != inferior_ptid.pid ())
- {
- pid = -1;
- save_errno = EINTR;
- }
-
- clear_sigint_trap ();
- }
- while (pid == -1 && save_errno == EINTR);
-
- if (pid == -1)
- {
- warning (_("Child process unexpectedly missing: %s"),
- safe_strerror (save_errno));
-
- /* Claim it exited with unknown signal. */
- ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
- ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
- return inferior_ptid;
- }
-
- store_waitstatus (ourstatus, status);
- return ptid_t (pid);
-}
-
-/* Override the fetch_inferior_register routine. */
-void
-spu_linux_nat_target::fetch_registers (struct regcache *regcache, int regno)
-{
- int fd;
- ULONGEST addr;
-
- /* Since we use functions that rely on inferior_ptid, we need to set and
- restore it. */
- scoped_restore save_ptid
- = make_scoped_restore (&inferior_ptid, regcache->ptid ());
-
- /* We must be stopped on a spu_run system call. */
- if (!parse_spufs_run (&fd, &addr))
- return;
-
- /* The ID register holds the spufs file handle. */
- if (regno == -1 || regno == SPU_ID_REGNUM)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte buf[4];
- store_unsigned_integer (buf, 4, byte_order, fd);
- regcache->raw_supply (SPU_ID_REGNUM, buf);
- }
-
- /* The NPC register is found at ADDR. */
- if (regno == -1 || regno == SPU_PC_REGNUM)
- {
- gdb_byte buf[4];
- if (fetch_ppc_memory (addr, buf, 4) == 0)
- regcache->raw_supply (SPU_PC_REGNUM, buf);
- }
-
- /* The GPRs are found in the "regs" spufs file. */
- if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
- {
- gdb_byte buf[16 * SPU_NUM_GPRS];
- char annex[32];
- int i;
- ULONGEST len;
-
- xsnprintf (annex, sizeof annex, "%d/regs", fd);
- if ((spu_proc_xfer_spu (annex, buf, NULL, 0, sizeof buf, &len)
- == TARGET_XFER_OK)
- && len == sizeof buf)
- for (i = 0; i < SPU_NUM_GPRS; i++)
- regcache->raw_supply (i, buf + i*16);
- }
-}
-
-/* Override the store_inferior_register routine. */
-void
-spu_linux_nat_target::store_registers (struct regcache *regcache, int regno)
-{
- int fd;
- ULONGEST addr;
-
- /* Since we use functions that rely on inferior_ptid, we need to set and
- restore it. */
- scoped_restore save_ptid
- = make_scoped_restore (&inferior_ptid, regcache->ptid ());
-
- /* We must be stopped on a spu_run system call. */
- if (!parse_spufs_run (&fd, &addr))
- return;
-
- /* The NPC register is found at ADDR. */
- if (regno == -1 || regno == SPU_PC_REGNUM)
- {
- gdb_byte buf[4];
- regcache->raw_collect (SPU_PC_REGNUM, buf);
- store_ppc_memory (addr, buf, 4);
- }
-
- /* The GPRs are found in the "regs" spufs file. */
- if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
- {
- gdb_byte buf[16 * SPU_NUM_GPRS];
- char annex[32];
- int i;
- ULONGEST len;
-
- for (i = 0; i < SPU_NUM_GPRS; i++)
- regcache->raw_collect (i, buf + i*16);
-
- xsnprintf (annex, sizeof annex, "%d/regs", fd);
- spu_proc_xfer_spu (annex, NULL, buf, 0, sizeof buf, &len);
- }
-}
-
-/* Override the to_xfer_partial routine. */
-enum target_xfer_status
-spu_linux_nat_target::xfer_partial (enum target_object object, const char *annex,
- gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len)
-{
- if (object == TARGET_OBJECT_SPU)
- return spu_proc_xfer_spu (annex, readbuf, writebuf, offset, len,
- xfered_len);
-
- if (object == TARGET_OBJECT_MEMORY)
- {
- int fd;
- ULONGEST addr;
- char mem_annex[32], lslr_annex[32];
- gdb_byte buf[32];
- ULONGEST lslr;
- enum target_xfer_status ret;
-
- /* We must be stopped on a spu_run system call. */
- if (!parse_spufs_run (&fd, &addr))
- return TARGET_XFER_EOF;
-
- /* Use the "mem" spufs file to access SPU local store. */
- xsnprintf (mem_annex, sizeof mem_annex, "%d/mem", fd);
- ret = spu_proc_xfer_spu (mem_annex, readbuf, writebuf, offset, len,
- xfered_len);
- if (ret == TARGET_XFER_OK)
- return ret;
-
- /* SPU local store access wraps the address around at the
- local store limit. We emulate this here. To avoid needing
- an extra access to retrieve the LSLR, we only do that after
- trying the original address first, and getting end-of-file. */
- xsnprintf (lslr_annex, sizeof lslr_annex, "%d/lslr", fd);
- memset (buf, 0, sizeof buf);
- if (spu_proc_xfer_spu (lslr_annex, buf, NULL, 0, sizeof buf, xfered_len)
- != TARGET_XFER_OK)
- return ret;
-
- lslr = strtoulst ((const char *) buf, NULL, 16);
- return spu_proc_xfer_spu (mem_annex, readbuf, writebuf,
- offset & lslr, len, xfered_len);
- }
-
- return TARGET_XFER_E_IO;
-}
-
-/* Override the to_can_use_hw_breakpoint routine. */
-int
-spu_linux_nat_target::can_use_hw_breakpoint (enum bptype type,
- int cnt, int othertype)
-{
- return 0;
-}
-
-/* Initialize SPU native target. */
-void
-_initialize_spu_nat (void)
-{
- add_inf_child_target (&the_spu_linux_nat_target);
-}