* config/powerpc/spu-linux.mh: New file.
* config/spu/spu.mt: New file. * configure.ac: Provide gdb_native configuration variable. * configure: Regenerate. * configure.host: Support powerpc64 to spu 'pseudo-native' mode. * configure.tgt: Add "spu" target_cpu and "spu*-*-*" target. * Makefile.in (spu_tdep_h): New variable. (ALLDEPFILES): Add spu-linux-nat.c and spu-tdep.c (spu-linux-nat.o, spu-tdep.o): Add dependencies. * spu-linux-nat.c: New file. * spu-tdep.c: New file. * spu-tdep.h: New file.
This commit is contained in:
parent
0b2b0195d1
commit
771b4502d5
@ -1,3 +1,18 @@
|
||||
2006-11-22 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* config/powerpc/spu-linux.mh: New file.
|
||||
* config/spu/spu.mt: New file.
|
||||
* configure.ac: Provide gdb_native configuration variable.
|
||||
* configure: Regenerate.
|
||||
* configure.host: Support powerpc64 to spu 'pseudo-native' mode.
|
||||
* configure.tgt: Add "spu" target_cpu and "spu*-*-*" target.
|
||||
* Makefile.in (spu_tdep_h): New variable.
|
||||
(ALLDEPFILES): Add spu-linux-nat.c and spu-tdep.c
|
||||
(spu-linux-nat.o, spu-tdep.o): Add dependencies.
|
||||
* spu-linux-nat.c: New file.
|
||||
* spu-tdep.c: New file.
|
||||
* spu-tdep.h: New file.
|
||||
|
||||
2006-11-22 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* findvar.c (address_from_register): New function.
|
||||
|
@ -799,6 +799,7 @@ source_h = source.h
|
||||
sparc64_tdep_h = sparc64-tdep.h $(sparc_tdep_h)
|
||||
sparc_nat_h = sparc-nat.h
|
||||
sparc_tdep_h = sparc-tdep.h
|
||||
spu_tdep_h = spu-tdep.h
|
||||
srec_h = srec.h
|
||||
stabsread_h = stabsread.h
|
||||
stack_h = stack.h
|
||||
@ -1497,6 +1498,7 @@ ALLDEPFILES = \
|
||||
sparc64-tdep.c sparc64fbsd-nat.c sparc64fbsd-tdep.c \
|
||||
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
|
||||
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
|
||||
spu-linux-nat.c spu-tdep.c \
|
||||
v850-tdep.c \
|
||||
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
|
||||
win32-nat.c \
|
||||
@ -2721,6 +2723,15 @@ sparc-tdep.o: sparc-tdep.c $(defs_h) $(arch_utils_h) $(dis_asm_h) \
|
||||
$(frame_unwind_h) $(gdbcore_h) $(gdbtypes_h) $(inferior_h) \
|
||||
$(symtab_h) $(objfiles_h) $(osabi_h) $(regcache_h) $(target_h) \
|
||||
$(value_h) $(gdb_assert_h) $(gdb_string_h) $(sparc_tdep_h)
|
||||
spu-linux-nat.o: spu-linux-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h) \
|
||||
$(target_h) $(inferior_h) $(inf_ptrace_h) $(regcache_h) $(symfile_h) \
|
||||
$(gdb_wait_h) $(spu_tdep_h)
|
||||
spu-tdep.o: spu-tdep.c $(defs_h) $(arch_utils_h) $(gdbtypes_h) $(gdbcmd_h) \
|
||||
$(gdbcore_h) $(gdb_string_h) $(gdb_assert_h) $(frame_h) \
|
||||
$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(symtab_h) \
|
||||
$(symfile_h) $(value_h) $(inferior_h) $(dis_asm_h) $(objfiles_h) \
|
||||
$(language_h) $(regcache_h) $(reggroups_h) $(floatformat_h) \
|
||||
$(spu_tdep_h)
|
||||
stabsread.o: stabsread.c $(defs_h) $(gdb_string_h) $(bfd_h) $(gdb_obstack_h) \
|
||||
$(symtab_h) $(gdbtypes_h) $(expression_h) $(symfile_h) $(objfiles_h) \
|
||||
$(aout_stab_gnu_h) $(libaout_h) $(aout_aout64_h) $(gdb_stabs_h) \
|
||||
|
7
gdb/config/powerpc/spu-linux.mh
Normal file
7
gdb/config/powerpc/spu-linux.mh
Normal file
@ -0,0 +1,7 @@
|
||||
# Target: Cell BE (PowerPC64 + SPU)
|
||||
|
||||
# This implements a 'pseudo-native' GDB running on the
|
||||
# PPU side of the Cell BE and debugging the SPU side.
|
||||
|
||||
NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o
|
||||
|
2
gdb/config/spu/spu.mt
Normal file
2
gdb/config/spu/spu.mt
Normal file
@ -0,0 +1,2 @@
|
||||
# Target: Cell BE SPU
|
||||
TDEPFILES= spu-tdep.o
|
20
gdb/configure
vendored
20
gdb/configure
vendored
@ -3062,6 +3062,12 @@ subdirs="$subdirs doc testsuite"
|
||||
# configuration.
|
||||
gdb_host_obs=posix-hdep.o
|
||||
|
||||
if test "${target}" = "${host}"; then
|
||||
gdb_native=yes
|
||||
else
|
||||
gdb_native=no
|
||||
fi
|
||||
|
||||
. $srcdir/configure.host
|
||||
|
||||
. $srcdir/configure.tgt
|
||||
@ -22335,7 +22341,7 @@ ac_x_header_dirs='
|
||||
/usr/openwin/share/include'
|
||||
|
||||
if test "$ac_x_includes" = no; then
|
||||
# Guess where to find include files, by looking for Intrinsic.h.
|
||||
# Guess where to find include files, by looking for Xlib.h.
|
||||
# First, try using that file with no special directory specified.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
@ -22343,7 +22349,7 @@ _ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <X11/Intrinsic.h>
|
||||
#include <X11/Xlib.h>
|
||||
_ACEOF
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
|
||||
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
|
||||
@ -22370,7 +22376,7 @@ else
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
for ac_dir in $ac_x_header_dirs; do
|
||||
if test -r "$ac_dir/X11/Intrinsic.h"; then
|
||||
if test -r "$ac_dir/X11/Xlib.h"; then
|
||||
ac_x_includes=$ac_dir
|
||||
break
|
||||
fi
|
||||
@ -22391,11 +22397,11 @@ _ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <X11/Intrinsic.h>
|
||||
#include <X11/Xlib.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
XtMalloc (0)
|
||||
XrmInitialize ()
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@ -22572,7 +22578,7 @@ fi
|
||||
|
||||
|
||||
frags=
|
||||
if test "${target}" = "${host}"; then
|
||||
if test "${gdb_native}" = "yes"; then
|
||||
host_makefile_frag=${srcdir}/config/${gdb_host_cpu}/${gdb_host}.mh
|
||||
if test ! -f ${host_makefile_frag}; then
|
||||
{ { echo "$as_me:$LINENO: error: \"*** Gdb does not support native target ${host}\"" >&5
|
||||
@ -22604,7 +22610,7 @@ targetfile=`sed -n '
|
||||
s/DEPRECATED_TM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p
|
||||
' ${target_makefile_frag}`
|
||||
|
||||
if test "${target}" = "${host}"; then
|
||||
if test "${gdb_native}" = "yes"; then
|
||||
# We pick this up from the host configuration file (.mh) because we
|
||||
# do not have a native configuration Makefile fragment.
|
||||
nativefile=`sed -n '
|
||||
|
@ -81,6 +81,12 @@ AC_CONFIG_SUBDIRS(doc testsuite)
|
||||
# configuration.
|
||||
gdb_host_obs=posix-hdep.o
|
||||
|
||||
if test "${target}" = "${host}"; then
|
||||
gdb_native=yes
|
||||
else
|
||||
gdb_native=no
|
||||
fi
|
||||
|
||||
. $srcdir/configure.host
|
||||
|
||||
. $srcdir/configure.tgt
|
||||
@ -1420,7 +1426,7 @@ fi
|
||||
AC_SUBST(target_subdir)
|
||||
|
||||
frags=
|
||||
if test "${target}" = "${host}"; then
|
||||
if test "${gdb_native}" = "yes"; then
|
||||
host_makefile_frag=${srcdir}/config/${gdb_host_cpu}/${gdb_host}.mh
|
||||
if test ! -f ${host_makefile_frag}; then
|
||||
AC_MSG_ERROR("*** Gdb does not support native target ${host}")
|
||||
@ -1449,7 +1455,7 @@ targetfile=`sed -n '
|
||||
s/DEPRECATED_TM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p
|
||||
' ${target_makefile_frag}`
|
||||
|
||||
if test "${target}" = "${host}"; then
|
||||
if test "${gdb_native}" = "yes"; then
|
||||
# We pick this up from the host configuration file (.mh) because we
|
||||
# do not have a native configuration Makefile fragment.
|
||||
nativefile=`sed -n '
|
||||
|
@ -114,7 +114,13 @@ powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
|
||||
gdb_host=nbsd ;;
|
||||
powerpc-*-openbsd*) gdb_host=obsd ;;
|
||||
|
||||
powerpc64-*-linux*) gdb_host=ppc64-linux ;;
|
||||
powerpc64-*-linux*) gdb_host=ppc64-linux
|
||||
# Support 'pseudo-native' debugging on the Cell BE
|
||||
if test "${target_cpu}" = "spu"; then
|
||||
gdb_host=spu-linux
|
||||
gdb_native=yes
|
||||
fi
|
||||
;;
|
||||
|
||||
rs6000-*-lynxos*) gdb_host=rs6000lynx ;;
|
||||
rs6000-*-aix4*) gdb_host=aix4 ;;
|
||||
|
@ -25,6 +25,7 @@ sparc*) gdb_target_cpu=sparc ;;
|
||||
thumb*) gdb_target_cpu=arm ;;
|
||||
s390*) gdb_target_cpu=s390 ;;
|
||||
sh*) gdb_target_cpu=sh ;;
|
||||
spu*) gdb_target_cpu=spu ;;
|
||||
strongarm*) gdb_target_cpu=arm ;;
|
||||
xscale*) gdb_target_cpu=arm ;;
|
||||
x86_64*) gdb_target_cpu=i386 ;;
|
||||
@ -209,6 +210,8 @@ sparc-*-rtems*) gdb_target=embed ;;
|
||||
sparc-*-*) gdb_target=sparc ;;
|
||||
sparc64-*-*) gdb_target=sparc64 ;;
|
||||
|
||||
spu*-*-*) gdb_target=spu ;;
|
||||
|
||||
xstormy16-*-*) gdb_target=xstormy16 ;;
|
||||
|
||||
v850*-*-elf) gdb_target=v850 ;;
|
||||
|
557
gdb/spu-linux-nat.c
Normal file
557
gdb/spu-linux-nat.c
Normal file
@ -0,0 +1,557 @@
|
||||
/* SPU native-dependent code for GDB, the GNU debugger.
|
||||
Copyright (C) 2006 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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdb_string.h"
|
||||
#include "target.h"
|
||||
#include "inferior.h"
|
||||
#include "inf-ptrace.h"
|
||||
#include "regcache.h"
|
||||
#include "symfile.h"
|
||||
#include "gdb_wait.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "spu-tdep.h"
|
||||
|
||||
/* PPU side system calls. */
|
||||
#define INSTR_SC 0x44000002
|
||||
#define NR_spu_run 0x0116
|
||||
|
||||
|
||||
/* Fetch PPU register REGNO. */
|
||||
static CORE_ADDR
|
||||
fetch_ppc_register (int regno)
|
||||
{
|
||||
PTRACE_TYPE_RET res;
|
||||
|
||||
int tid = TIDGET (inferior_ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (inferior_ptid);
|
||||
|
||||
#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 (CORE_ADDR) *(unsigned long long *)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 (CORE_ADDR) (unsigned long) res;
|
||||
}
|
||||
|
||||
/* Fetch WORD from PPU memory at (aligned) MEMADDR in thread TID. */
|
||||
static int
|
||||
fetch_ppc_memory_1 (int tid, CORE_ADDR memaddr, PTRACE_TYPE_RET *word)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
#ifndef __powerpc64__
|
||||
if (memaddr >> 32)
|
||||
{
|
||||
unsigned long long addr_8 = (unsigned long long) 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, CORE_ADDR memaddr, PTRACE_TYPE_RET word)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
#ifndef __powerpc64__
|
||||
if (memaddr >> 32)
|
||||
{
|
||||
unsigned long long addr_8 = (unsigned long long) 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 (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_TYPE_RET);
|
||||
int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
|
||||
/ sizeof (PTRACE_TYPE_RET));
|
||||
PTRACE_TYPE_RET *buffer;
|
||||
|
||||
int tid = TIDGET (inferior_ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (inferior_ptid);
|
||||
|
||||
buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
|
||||
for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
|
||||
if ((ret = fetch_ppc_memory_1 (tid, addr, &buffer[i])) != 0)
|
||||
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 (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_TYPE_RET);
|
||||
int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
|
||||
/ sizeof (PTRACE_TYPE_RET));
|
||||
PTRACE_TYPE_RET *buffer;
|
||||
|
||||
int tid = TIDGET (inferior_ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (inferior_ptid);
|
||||
|
||||
buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
|
||||
|
||||
if (addr != memaddr || len < (int) sizeof (PTRACE_TYPE_RET))
|
||||
if ((ret = fetch_ppc_memory_1 (tid, addr, &buffer[0])) != 0)
|
||||
return ret;
|
||||
|
||||
if (count > 1)
|
||||
if ((ret = fetch_ppc_memory_1 (tid, addr + (count - 1)
|
||||
* sizeof (PTRACE_TYPE_RET),
|
||||
&buffer[count - 1])) != 0)
|
||||
return ret;
|
||||
|
||||
memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
|
||||
myaddr, len);
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
|
||||
if ((ret = store_ppc_memory_1 (tid, addr, buffer[i])) != 0)
|
||||
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, CORE_ADDR *addr)
|
||||
{
|
||||
gdb_byte buf[4];
|
||||
CORE_ADDR 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) != 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;
|
||||
}
|
||||
|
||||
|
||||
/* Copy LEN bytes at OFFSET in spufs file ANNEX into/from READBUF or WRITEBUF,
|
||||
using the /proc file system. */
|
||||
static LONGEST
|
||||
spu_proc_xfer_spu (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)
|
||||
return 0;
|
||||
|
||||
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 -1;
|
||||
}
|
||||
|
||||
if (writebuf)
|
||||
ret = write (fd, writebuf, (size_t) len);
|
||||
else if (readbuf)
|
||||
ret = read (fd, readbuf, (size_t) len);
|
||||
|
||||
close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static file_ptr
|
||||
spu_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
|
||||
file_ptr nbytes, file_ptr offset)
|
||||
{
|
||||
CORE_ADDR addr = *(CORE_ADDR *)stream;
|
||||
|
||||
if (fetch_ppc_memory (addr + offset, buf, nbytes) != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_invalid_operation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static bfd *
|
||||
spu_bfd_open (CORE_ADDR addr)
|
||||
{
|
||||
struct bfd *nbfd;
|
||||
|
||||
CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
|
||||
*open_closure = addr;
|
||||
|
||||
nbfd = bfd_openr_iovec (xstrdup ("<in-memory>"), "elf32-spu",
|
||||
spu_bfd_iovec_open, open_closure,
|
||||
spu_bfd_iovec_pread, spu_bfd_iovec_close);
|
||||
if (!nbfd)
|
||||
return NULL;
|
||||
|
||||
if (!bfd_check_format (nbfd, bfd_object))
|
||||
{
|
||||
bfd_close (nbfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
struct bfd *nbfd;
|
||||
|
||||
char id[128];
|
||||
char annex[32];
|
||||
int len;
|
||||
|
||||
/* Read object ID. */
|
||||
xsnprintf (annex, sizeof annex, "%d/object-id", inferior_fd);
|
||||
len = spu_proc_xfer_spu (annex, id, NULL, 0, sizeof id);
|
||||
if (len <= 0 || len >= sizeof id)
|
||||
return;
|
||||
id[len] = 0;
|
||||
if (sscanf (id, "0x%llx", &addr) != 1)
|
||||
return;
|
||||
|
||||
/* Open BFD representing SPE executable and read its symbols. */
|
||||
nbfd = spu_bfd_open (addr);
|
||||
if (nbfd)
|
||||
symbol_file_add_from_bfd (nbfd, 0, NULL, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Override the post_startup_inferior routine to continue running
|
||||
the inferior until the first spu_run system call. */
|
||||
static void
|
||||
spu_child_post_startup_inferior (ptid_t ptid)
|
||||
{
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
|
||||
int tid = TIDGET (ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (ptid);
|
||||
|
||||
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. */
|
||||
static void
|
||||
spu_child_post_attach (int pid)
|
||||
{
|
||||
int fd;
|
||||
CORE_ADDR 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. */
|
||||
static ptid_t
|
||||
spu_child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
int save_errno;
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
do
|
||||
{
|
||||
set_sigint_trap (); /* Causes SIGINT to be passed on to the
|
||||
attached process. */
|
||||
set_sigio_trap ();
|
||||
|
||||
pid = waitpid (PIDGET (ptid), &status, 0);
|
||||
if (pid == -1 && errno == ECHILD)
|
||||
/* Try again with __WCLONE to check cloned processes. */
|
||||
pid = waitpid (PIDGET (ptid), &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 != PIDGET (inferior_ptid))
|
||||
{
|
||||
pid = -1;
|
||||
save_errno = EINTR;
|
||||
}
|
||||
|
||||
clear_sigio_trap ();
|
||||
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 = TARGET_SIGNAL_UNKNOWN;
|
||||
return minus_one_ptid;
|
||||
}
|
||||
|
||||
store_waitstatus (ourstatus, status);
|
||||
return pid_to_ptid (pid);
|
||||
}
|
||||
|
||||
/* Override the fetch_inferior_register routine. */
|
||||
static void
|
||||
spu_fetch_inferior_registers (int regno)
|
||||
{
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
char buf[4];
|
||||
store_unsigned_integer (buf, 4, fd);
|
||||
regcache_raw_supply (current_regcache, 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 (current_regcache, 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;
|
||||
|
||||
xsnprintf (annex, sizeof annex, "%d/regs", fd);
|
||||
if (spu_proc_xfer_spu (annex, buf, NULL, 0, sizeof buf) == sizeof buf)
|
||||
for (i = 0; i < SPU_NUM_GPRS; i++)
|
||||
regcache_raw_supply (current_regcache, i, buf + i*16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Override the store_inferior_register routine. */
|
||||
static void
|
||||
spu_store_inferior_registers (int regno)
|
||||
{
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
|
||||
/* 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 (current_regcache, 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;
|
||||
|
||||
for (i = 0; i < SPU_NUM_GPRS; i++)
|
||||
regcache_raw_collect (current_regcache, i, buf + i*16);
|
||||
|
||||
xsnprintf (annex, sizeof annex, "%d/regs", fd);
|
||||
spu_proc_xfer_spu (annex, NULL, buf, 0, sizeof buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Override the to_xfer_partial routine. */
|
||||
static LONGEST
|
||||
spu_xfer_partial (struct target_ops *ops,
|
||||
enum target_object object, const char *annex,
|
||||
gdb_byte *readbuf, const gdb_byte *writebuf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
if (object == TARGET_OBJECT_MEMORY)
|
||||
{
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
char mem_annex[32];
|
||||
|
||||
/* We must be stopped on a spu_run system call. */
|
||||
if (!parse_spufs_run (&fd, &addr))
|
||||
return 0;
|
||||
|
||||
/* Use the "mem" spufs file to access SPU local store. */
|
||||
xsnprintf (mem_annex, sizeof mem_annex, "%d/mem", fd);
|
||||
return spu_proc_xfer_spu (mem_annex, readbuf, writebuf, offset, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Override the to_can_use_hw_breakpoint routine. */
|
||||
static int
|
||||
spu_can_use_hw_breakpoint (int type, int cnt, int othertype)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize SPU native target. */
|
||||
void
|
||||
_initialize_spu_nat (void)
|
||||
{
|
||||
/* Generic ptrace methods. */
|
||||
struct target_ops *t;
|
||||
t = inf_ptrace_target ();
|
||||
|
||||
/* Add SPU methods. */
|
||||
t->to_post_attach = spu_child_post_attach;
|
||||
t->to_post_startup_inferior = spu_child_post_startup_inferior;
|
||||
t->to_wait = spu_child_wait;
|
||||
t->to_fetch_registers = spu_fetch_inferior_registers;
|
||||
t->to_store_registers = spu_store_inferior_registers;
|
||||
t->to_xfer_partial = spu_xfer_partial;
|
||||
t->to_can_use_hw_breakpoint = spu_can_use_hw_breakpoint;
|
||||
|
||||
/* Register SPU target. */
|
||||
add_target (t);
|
||||
}
|
||||
|
1099
gdb/spu-tdep.c
Normal file
1099
gdb/spu-tdep.c
Normal file
File diff suppressed because it is too large
Load Diff
50
gdb/spu-tdep.h
Normal file
50
gdb/spu-tdep.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* SPU target-dependent code for GDB, the GNU debugger.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef SPU_TDEP_H
|
||||
#define SPU_TDEP_H
|
||||
|
||||
/* Number of registers. */
|
||||
#define SPU_NUM_REGS 130
|
||||
#define SPU_NUM_PSEUDO_REGS 1
|
||||
#define SPU_NUM_GPRS 128
|
||||
|
||||
/* Register numbers of various important registers. */
|
||||
enum spu_regnum
|
||||
{
|
||||
/* SPU calling convention. */
|
||||
SPU_LR_REGNUM = 0, /* Link register. */
|
||||
SPU_RAW_SP_REGNUM = 1, /* Stack pointer (full register). */
|
||||
SPU_ARG1_REGNUM = 3, /* First argument register. */
|
||||
SPU_ARGN_REGNUM = 74, /* Last argument register. */
|
||||
SPU_SAVED1_REGNUM = 80, /* First call-saved register. */
|
||||
SPU_SAVEDN_REGNUM = 127, /* Last call-saved register. */
|
||||
SPU_FP_REGNUM = 127, /* Frame pointer. */
|
||||
|
||||
/* Special registers. */
|
||||
SPU_ID_REGNUM = 128, /* SPU ID register. */
|
||||
SPU_PC_REGNUM = 129, /* Next program counter. */
|
||||
SPU_SP_REGNUM = 130 /* Stack pointer (preferred slot). */
|
||||
};
|
||||
|
||||
/* Local store. */
|
||||
#define SPU_LS_SIZE 0x40000
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user