ChangeLog:

* target.h (enum strata): New value arch_stratum.
	* target.c (target_require_runnable): Skip arch_stratum targets.

	* configure.tgt (powerpc-*-linux* | powerpc64-*-linux*): Add
	solib-spu.o and spu-multiarch.o to gdb_target_obs.
	* Makefile.in (ALL_TARGET_OBS): Add solib-spu.o and spu-multiarch.o.
	(ALLDEPFILES): Add solib-spu.c and spu-multiarch.c.

	* solib-spu.c: New file.
	* solib-spu.h: New file.
	* spu-multiarch.c: New file.

	* spu-tdep.h (SPUADDR, SPUADDR_SPU, SPUADDR_ADDR): New macros.

	* spu-tdep.c (struct gdbarch_tdep): New member id.
	(spu_gdbarch_id): New function.
	(spu_lslr): New function.

	(spu_address_to_pointer): New function.
	(spu_pointer_to_address): Support SPU ID address encoding.  Use
	spu_gdbarch_id and spu_lslr.
	(spu_integer_to_address): Likewise.
	(spu_frame_unwind_cache): Update for encoded addresses.
	(spu_unwind_pc, spu_unwind_sp): Likewise.
	(spu_read_pc, spu_write_pc): Likewise.
	(spu_push_dummy_call): Likewise.
	(spu_software_single_step): Likewise.
	(spu_get_longjmp_target): Likewise.
	(spu_overlay_update_osect): Likewise.

	(spu_dis_asm_print_address): New function.
	(gdb_print_insn_spu): Likewise.

	(spu_gdbarch_init): Store SPU ID in tdep structure.
	Install spu_address_to_pointer and gdb_print_insn_spu.

	* ppc-linux-tdep.c: Include "observer.h", "auxv.h", "elf/common.h"
	and "solib-spu.h".
	(ppc_linux_entry_point_addr): New static variable.
	(ppc_linux_inferior_created): New function.
	(ppc_linux_displaced_step_location): Likewise.
	(ppc_linux_init_abi): Enable Cell/B.E. support if supported
	by the target.
	(_initialize_ppc_linux_tdep): Attach to inferior_created observer.

	* NEWS: Mention multi-architecture and Cell/B.E. debugging
	capabilities.

testsuite/ChangeLog:

	* gdb.xml/tdesc-regs.exp: Skip for SPU targets.
This commit is contained in:
Ulrich Weigand 2009-07-31 15:28:27 +00:00
parent efcbbd1428
commit 85e747d249
14 changed files with 1175 additions and 46 deletions

View file

@ -1,3 +1,53 @@
2009-07-31 Ulrich Weigand <uweigand@de.ibm.com>
* target.h (enum strata): New value arch_stratum.
* target.c (target_require_runnable): Skip arch_stratum targets.
* configure.tgt (powerpc-*-linux* | powerpc64-*-linux*): Add
solib-spu.o and spu-multiarch.o to gdb_target_obs.
* Makefile.in (ALL_TARGET_OBS): Add solib-spu.o and spu-multiarch.o.
(ALLDEPFILES): Add solib-spu.c and spu-multiarch.c.
* solib-spu.c: New file.
* solib-spu.h: New file.
* spu-multiarch.c: New file.
* spu-tdep.h (SPUADDR, SPUADDR_SPU, SPUADDR_ADDR): New macros.
* spu-tdep.c (struct gdbarch_tdep): New member id.
(spu_gdbarch_id): New function.
(spu_lslr): New function.
(spu_address_to_pointer): New function.
(spu_pointer_to_address): Support SPU ID address encoding. Use
spu_gdbarch_id and spu_lslr.
(spu_integer_to_address): Likewise.
(spu_frame_unwind_cache): Update for encoded addresses.
(spu_unwind_pc, spu_unwind_sp): Likewise.
(spu_read_pc, spu_write_pc): Likewise.
(spu_push_dummy_call): Likewise.
(spu_software_single_step): Likewise.
(spu_get_longjmp_target): Likewise.
(spu_overlay_update_osect): Likewise.
(spu_dis_asm_print_address): New function.
(gdb_print_insn_spu): Likewise.
(spu_gdbarch_init): Store SPU ID in tdep structure.
Install spu_address_to_pointer and gdb_print_insn_spu.
* ppc-linux-tdep.c: Include "observer.h", "auxv.h", "elf/common.h"
and "solib-spu.h".
(ppc_linux_entry_point_addr): New static variable.
(ppc_linux_inferior_created): New function.
(ppc_linux_displaced_step_location): Likewise.
(ppc_linux_init_abi): Enable Cell/B.E. support if supported
by the target.
(_initialize_ppc_linux_tdep): Attach to inferior_created observer.
* NEWS: Mention multi-architecture and Cell/B.E. debugging
capabilities.
2009-07-31 Ulrich Weigand <uweigand@de.ibm.com>
* linux-nat.c: Include <sys/vfs.h>.

View file

@ -511,7 +511,7 @@ ALL_TARGET_OBS = \
sh64-tdep.o sh-linux-tdep.o shnbsd-tdep.o sh-tdep.o \
sparc-linux-tdep.o sparcnbsd-tdep.o sparcobsd-tdep.o \
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@ -1420,7 +1420,7 @@ ALLDEPFILES = \
sparc64-nat.c 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 \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \

View file

@ -209,6 +209,20 @@ architecture in addition to those for the main target architecture.
See the "Target Description Format" section in the user manual for
more information.
* Multi-architecture debugging.
GDB now includes general supports for debugging applications on
hybrid systems that use more than one single processor architecture
at the same time. Each such hybrid architecture still requires
specific support to be added. The only hybrid architecture supported
in this version of GDB is the Cell Broadband Engine.
* GDB now supports integrated debugging of Cell/B.E. applications that
use both the PPU and SPU architectures. To enable support for hybrid
Cell/B.E. debugging, you need to configure GDB to support both the
powerpc-linux or powerpc64-linux and the spu-elf targets, using the
--enable-targets configure option.
* New commands (for set/show, see "New options" below)
find [/size-char] [/max-count] start-address, end-address|+search-space-size,

View file

@ -375,7 +375,8 @@ powerpc-*-aix* | rs6000-*-*)
powerpc-*-linux* | powerpc64-*-linux*)
# Target: PowerPC running Linux
gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \
solib.o solib-svr4.o corelow.o symfile-mem.o"
solib.o solib-svr4.o solib-spu.o spu-multiarch.o \
corelow.o symfile-mem.o"
gdb_sim=../sim/ppc/libsim.a
build_gdbserver=yes
;;

View file

@ -33,11 +33,15 @@
#include "osabi.h"
#include "regset.h"
#include "solib-svr4.h"
#include "solib-spu.h"
#include "ppc-tdep.h"
#include "ppc-linux-tdep.h"
#include "trad-frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
#include "observer.h"
#include "auxv.h"
#include "elf/common.h"
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
@ -1003,6 +1007,46 @@ static struct tramp_frame ppc64_linux_sighandler_tramp_frame = {
};
/* Address to use for displaced stepping. When debugging a stand-alone
SPU executable, entry_point_address () will point to an SPU local-store
address and is thus not usable as displaced stepping location. We use
the auxiliary vector to determine the PowerPC-side entry point address
instead. */
static CORE_ADDR ppc_linux_entry_point_addr = 0;
static void
ppc_linux_inferior_created (struct target_ops *target, int from_tty)
{
ppc_linux_entry_point_addr = 0;
}
static CORE_ADDR
ppc_linux_displaced_step_location (struct gdbarch *gdbarch)
{
if (ppc_linux_entry_point_addr == 0)
{
CORE_ADDR addr;
/* Determine entry point from target auxiliary vector. */
if (target_auxv_search (&current_target, AT_ENTRY, &addr) <= 0)
error (_("Cannot find AT_ENTRY auxiliary vector entry."));
/* Make certain that the address points at real code, and not a
function descriptor. */
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
&current_target);
/* Inferior calls also use the entry point as a breakpoint location.
We don't want displaced stepping to interfere with those
breakpoints, so leave space. */
ppc_linux_entry_point_addr = addr + 2 * PPC_INSN_SIZE;
}
return ppc_linux_entry_point_addr;
}
/* Return 1 if PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM are usable. */
int
ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
@ -1189,6 +1233,19 @@ ppc_linux_init_abi (struct gdbarch_info info,
PPC_TRAP_REGNUM, "trap");
}
}
/* Enable Cell/B.E. if supported by the target. */
if (tdesc_compatible_p (info.target_desc,
bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu)))
{
/* Cell/B.E. multi-architecture support. */
set_spu_solib_ops (gdbarch);
/* The default displaced_step_at_entry_point doesn't work for
SPU stand-alone executables. */
set_gdbarch_displaced_step_location (gdbarch,
ppc_linux_displaced_step_location);
}
}
/* Provide a prototype to silence -Wmissing-prototypes. */
@ -1206,6 +1263,9 @@ _initialize_ppc_linux_tdep (void)
gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
ppc_linux_init_abi);
/* Attach to inferior_created observer. */
observer_attach_inferior_created (ppc_linux_inferior_created);
/* Initialize the Linux target descriptions. */
initialize_tdesc_powerpc_32l ();
initialize_tdesc_powerpc_altivec32l ();

455
gdb/solib-spu.c Normal file
View file

@ -0,0 +1,455 @@
/* Cell SPU GNU/Linux support -- shared library handling.
Copyright (C) 2009 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "gdb_assert.h"
#include "gdb_stat.h"
#include "arch-utils.h"
#include "bfd.h"
#include "symtab.h"
#include "solib.h"
#include "solib-svr4.h"
#include "solist.h"
#include "inferior.h"
#include "objfiles.h"
#include "observer.h"
#include "breakpoint.h"
#include "gdbthread.h"
#include "spu-tdep.h"
/* Highest SPE id (file handle) the inferior may have. */
#define MAX_SPE_FD 1024
/* Stand-alone SPE executable? */
#define spu_standalone_p() \
(symfile_objfile && symfile_objfile->obfd \
&& bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
/* Relocate main SPE executable. */
static void
spu_relocate_main_executable (int spufs_fd)
{
struct objfile *objfile;
struct cleanup *old_chain;
struct section_offsets *new_offsets;
int i;
for (objfile = symfile_objfile;
objfile;
objfile = objfile->separate_debug_objfile)
{
new_offsets = xcalloc (objfile->num_sections,
sizeof (struct section_offsets));
old_chain = make_cleanup (xfree, new_offsets);
for (i = 0; i < objfile->num_sections; i++)
new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
objfile_relocate (objfile, new_offsets);
do_cleanups (old_chain);
}
}
/* When running a stand-alone SPE executable, we may need to skip one more
exec event on startup, to get past the binfmt_misc loader. */
static void
spu_skip_standalone_loader (void)
{
if (target_has_execution && !current_inferior ()->attach_flag)
{
struct target_waitstatus ws;
/* Only some kernels report an extra SIGTRAP with the binfmt_misc
loader; others do not. In addition, if we have attached to an
already running inferior instead of starting a new one, we will
not see the extra SIGTRAP -- and we cannot readily distinguish
the two cases, in particular with the extended-remote target.
Thus we issue a single-step here. If no extra SIGTRAP was pending,
this will step past the first instruction of the stand-alone SPE
executable loader, but we don't care about that. */
inferior_thread ()->in_infcall = 1; /* Suppress MI messages. */
target_resume (inferior_ptid, 1, TARGET_SIGNAL_0);
target_wait (minus_one_ptid, &ws, 0);
set_executing (minus_one_ptid, 0);
inferior_thread ()->in_infcall = 0;
}
}
/* Build a list of `struct so_list' objects describing the shared
objects currently loaded in the inferior. */
static struct so_list *
spu_current_sos (void)
{
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
struct so_list *head;
struct so_list **link_ptr;
char buf[MAX_SPE_FD * 4];
int i, size;
/* First, retrieve the SVR4 shared library list. */
head = svr4_so_ops.current_sos ();
/* Append our libraries to the end of the list. */
for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next)
;
/* Determine list of SPU ids. */
size = target_read (&current_target, TARGET_OBJECT_SPU, NULL,
buf, 0, sizeof buf);
/* Do not add stand-alone SPE executable context as shared library,
but relocate main SPE executable objfile. */
if (spu_standalone_p ())
{
if (size == 4)
{
int fd = extract_unsigned_integer (buf, 4, byte_order);
spu_relocate_main_executable (fd);
/* Re-enable breakpoints after main SPU context was established;
see also comments in spu_solib_create_inferior_hook. */
enable_breakpoints_after_startup ();
}
return head;
}
/* Create an so_list entry for each SPU id. */
for (i = 0; i < size; i += 4)
{
int fd = extract_unsigned_integer (buf + i, 4, byte_order);
struct so_list *new;
unsigned long long addr;
char annex[32], id[100];
int len;
/* Read object ID. There's a race window where the inferior may have
already created the SPE context, but not installed the object-id
yet. Skip such entries; we'll be back for them later. */
xsnprintf (annex, sizeof annex, "%d/object-id", fd);
len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
id, 0, sizeof id);
if (len <= 0 || len >= sizeof id)
continue;
id[len] = 0;
if (sscanf (id, "0x%llx", &addr) != 1 || !addr)
continue;
/* Allocate so_list structure. */
new = XZALLOC (struct so_list);
/* Encode FD and object ID in path name. Choose the name so as not
to conflict with any (normal) SVR4 library path name. */
xsnprintf (new->so_name, sizeof new->so_name, "@0x%llx <%d>", addr, fd);
strcpy (new->so_original_name, new->so_name);
*link_ptr = new;
link_ptr = &new->next;
}
return head;
}
/* Free so_list information. */
static void
spu_free_so (struct so_list *so)
{
if (so->so_original_name[0] != '@')
svr4_so_ops.free_so (so);
}
/* Relocate section addresses. */
static void
spu_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
if (so->so_original_name[0] != '@')
svr4_so_ops.relocate_section_addresses (so, sec);
else
{
unsigned long long addr;
int fd;
/* Set addr_low/high to just LS offset for display. */
if (so->addr_low == 0 && so->addr_high == 0
&& strcmp (sec->the_bfd_section->name, ".text") == 0)
{
so->addr_low = sec->addr;
so->addr_high = sec->endaddr;
}
/* Decode object ID. */
if (sscanf (so->so_original_name, "@0x%llx <%d>", &addr, &fd) != 2)
internal_error (__FILE__, __LINE__, "bad object ID");
sec->addr = SPUADDR (fd, sec->addr);
sec->endaddr = SPUADDR (fd, sec->endaddr);
}
}
/* 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 (bfd *nbfd, void *open_closure)
{
return open_closure;
}
static int
spu_bfd_iovec_close (bfd *nbfd, void *stream)
{
xfree (stream);
return 1;
}
static file_ptr
spu_bfd_iovec_pread (bfd *abfd, void *stream, void *buf,
file_ptr nbytes, file_ptr offset)
{
CORE_ADDR addr = *(CORE_ADDR *)stream;
int ret;
ret = target_read_memory (addr + offset, buf, nbytes);
if (ret != 0)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
return nbytes;
}
static int
spu_bfd_iovec_stat (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. */
sb->st_size = INT_MAX;
return 0;
}
static bfd *
spu_bfd_fopen (char *name, CORE_ADDR addr)
{
bfd *nbfd;
CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
*open_closure = addr;
nbfd = bfd_openr_iovec (xstrdup (name), "elf32-spu",
spu_bfd_iovec_open, open_closure,
spu_bfd_iovec_pread, spu_bfd_iovec_close,
spu_bfd_iovec_stat);
if (!nbfd)
return NULL;
if (!bfd_check_format (nbfd, bfd_object))
{
bfd_close (nbfd);
return NULL;
}
return nbfd;
}
/* Open shared library BFD. */
static bfd *
spu_bfd_open (char *pathname)
{
char *original_name = strrchr (pathname, '@');
bfd *abfd;
asection *spu_name;
unsigned long long addr;
int fd;
/* Handle regular SVR4 libraries. */
if (!original_name)
return svr4_so_ops.bfd_open (pathname);
/* Decode object ID. */
if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2)
internal_error (__FILE__, __LINE__, "bad object ID");
/* Open BFD representing SPE executable. */
abfd = spu_bfd_fopen (original_name, (CORE_ADDR) addr);
if (!abfd)
error (_("Cannot read SPE executable at %s"), original_name);
/* Retrieve SPU name note. */
spu_name = bfd_get_section_by_name (abfd, ".note.spu_name");
if (spu_name)
{
int sect_size = bfd_section_size (abfd, spu_name);
if (sect_size > 20)
{
char *buf = alloca (sect_size - 20 + strlen (original_name) + 1);
bfd_get_section_contents (abfd, spu_name, buf, 20, sect_size - 20);
buf[sect_size - 20] = '\0';
strcat (buf, original_name);
xfree ((char *)abfd->filename);
abfd->filename = xstrdup (buf);
}
}
return abfd;
}
/* Lookup global symbol in a SPE executable. */
static struct symbol *
spu_lookup_lib_symbol (const struct objfile *objfile,
const char *name,
const char *linkage_name,
const domain_enum domain)
{
if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
return lookup_global_symbol_from_objfile (objfile, name, linkage_name,
domain);
if (svr4_so_ops.lookup_lib_global_symbol != NULL)
return svr4_so_ops.lookup_lib_global_symbol (objfile, name, linkage_name,
domain);
return NULL;
}
/* Enable shared library breakpoint. */
static int
spu_enable_break (struct objfile *objfile)
{
struct minimal_symbol *spe_event_sym = NULL;
/* The libspe library will call __spe_context_update_event whenever any
SPE context is allocated or destroyed. */
spe_event_sym = lookup_minimal_symbol ("__spe_context_update_event",
NULL, objfile);
/* Place a solib_event breakpoint on the symbol. */
if (spe_event_sym)
{
CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, addr,
&current_target);
create_solib_event_breakpoint (target_gdbarch, addr);
return 1;
}
return 0;
}
/* Create inferior hook. */
static void
spu_solib_create_inferior_hook (void)
{
/* Remove all previously installed solib breakpoints. Both the SVR4
code and us will re-install all required breakpoints. */
remove_solib_event_breakpoints ();
/* Handle SPE stand-alone executables. */
if (spu_standalone_p ())
{
/* After an SPE stand-alone executable was loaded, we'll receive
an additional trap due to the binfmt_misc handler. Make sure
to skip that trap. */
spu_skip_standalone_loader ();
/* If the user established breakpoints before starting the inferior, GDB
would attempt to insert those now. This would fail because the SPU
context has not yet been created and the SPU executable has not yet
been loaded. To prevent such failures, we disable all user-created
breakpoints now; they will be re-enabled in spu_current_sos once the
main SPU context has been detected. */
disable_breakpoints_before_startup ();
/* A special case arises when re-starting an executable, because at
this point it still resides at the relocated address range that was
determined during its last execution. We need to undo the relocation
so that that multi-architecture target recognizes the stand-alone
initialization special case. */
spu_relocate_main_executable (-1);
}
/* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints. */
svr4_so_ops.solib_create_inferior_hook ();
/* If the inferior is statically linked against libspe, we need to install
our own solib breakpoint right now. Otherwise, it will be installed by
the solib_loaded observer below as soon as libspe is loaded. */
spu_enable_break (NULL);
}
/* Install SPE "shared library" handling. This is called by -tdep code
that wants to support SPU as a secondary architecture. */
void
set_spu_solib_ops (struct gdbarch *gdbarch)
{
static struct target_so_ops spu_so_ops;
/* Initialize this lazily, to avoid an initialization order
dependency on solib-svr4.c's _initialize routine. */
if (spu_so_ops.current_sos == NULL)
{
spu_so_ops = svr4_so_ops;
spu_so_ops.solib_create_inferior_hook = spu_solib_create_inferior_hook;
spu_so_ops.relocate_section_addresses = spu_relocate_section_addresses;
spu_so_ops.free_so = spu_free_so;
spu_so_ops.current_sos = spu_current_sos;
spu_so_ops.bfd_open = spu_bfd_open;
spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
}
set_solib_ops (gdbarch, &spu_so_ops);
}
/* Observer for the solib_loaded event. Used to install our breakpoint
if libspe is a shared library. */
static void
spu_solib_loaded (struct so_list *so)
{
if (strstr (so->so_original_name, "/libspe") != NULL)
{
solib_read_symbols (so, so->from_tty ? SYMFILE_VERBOSE : 0);
spu_enable_break (so->objfile);
}
}
void
_initialize_spu_solib (void)
{
observer_attach_solib_loaded (spu_solib_loaded);
}

25
gdb/solib-spu.h Normal file
View file

@ -0,0 +1,25 @@
/* Cell SPU GNU/Linux support -- shared library handling.
Copyright (C) 2009 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 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/>. */
#ifndef SOLIB_SPU_H
#define SOLIB_SPU_H
extern void set_spu_solib_ops (struct gdbarch *gdbarch);
#endif

397
gdb/spu-multiarch.c Normal file
View file

@ -0,0 +1,397 @@
/* Cell SPU GNU/Linux multi-architecture debugging support.
Copyright (C) 2009 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "gdb_string.h"
#include "gdb_assert.h"
#include "arch-utils.h"
#include "observer.h"
#include "inferior.h"
#include "regcache.h"
#include "symfile.h"
#include "objfiles.h"
#include "solib.h"
#include "solist.h"
#include "ppc-tdep.h"
#include "ppc-linux-tdep.h"
#include "spu-tdep.h"
/* This module's target vector. */
static struct target_ops spu_ops;
/* Number of SPE objects loaded into the current inferior. */
static int spu_nr_solib;
/* Stand-alone SPE executable? */
#define spu_standalone_p() \
(symfile_objfile && symfile_objfile->obfd \
&& bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
/* PPU side system calls. */
#define INSTR_SC 0x44000002
#define NR_spu_run 0x0116
/* 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 (ptid_t ptid, int *fd, CORE_ADDR *addr)
{
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
struct gdbarch_tdep *tdep;
struct regcache *regcache;
char buf[4];
CORE_ADDR pc;
ULONGEST regval;
/* If we're not on PPU, there's nothing to detect. */
if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_powerpc)
return 0;
/* Get PPU-side registers. */
regcache = get_thread_arch_regcache (ptid, target_gdbarch);
tdep = gdbarch_tdep (target_gdbarch);
/* Fetch instruction preceding current NIP. */
if (target_read_memory (regcache_read_pc (regcache) - 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. */
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum, &regval);
if (regval != NR_spu_run)
return 0;
/* Register 3 contains fd, register 4 the NPC param pointer. */
regcache_cooked_read_unsigned (regcache, PPC_ORIG_R3_REGNUM, &regval);
*fd = (int) regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 4, &regval);
*addr = (CORE_ADDR) regval;
return 1;
}
/* Find gdbarch for SPU context SPUFS_FD. */
static struct gdbarch *
spu_gdbarch (int spufs_fd)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
info.byte_order = BFD_ENDIAN_BIG;
info.osabi = GDB_OSABI_LINUX;
info.tdep_info = (void *) &spufs_fd;
return gdbarch_find_by_info (info);
}
/* Override the to_thread_architecture routine. */
static struct gdbarch *
spu_thread_architecture (struct target_ops *ops, ptid_t ptid)
{
int spufs_fd;
CORE_ADDR spufs_addr;
if (parse_spufs_run (ptid, &spufs_fd, &spufs_addr))
return spu_gdbarch (spufs_fd);
return target_gdbarch;
}
/* Override the to_region_ok_for_hw_watchpoint routine. */
static int
spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
ops_beneath = find_target_beneath (ops_beneath);
/* We cannot watch SPU local store. */
if (SPUADDR_SPU (addr) != -1)
return 0;
if (ops_beneath)
return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len);
return 0;
}
/* Override the to_fetch_registers routine. */
static void
spu_fetch_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct target_ops *ops_beneath = find_target_beneath (ops);
int spufs_fd;
CORE_ADDR spufs_addr;
/* This version applies only if we're currently in spu_run. */
if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu)
{
while (ops_beneath && !ops_beneath->to_fetch_registers)
ops_beneath = find_target_beneath (ops_beneath);
gdb_assert (ops_beneath);
ops_beneath->to_fetch_registers (ops_beneath, regcache, regno);
return;
}
/* We must be stopped on a spu_run system call. */
if (!parse_spufs_run (inferior_ptid, &spufs_fd, &spufs_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, byte_order, spufs_fd);
regcache_raw_supply (regcache, SPU_ID_REGNUM, buf);
}
/* The NPC register is found in PPC memory at SPUFS_ADDR. */
if (regno == -1 || regno == SPU_PC_REGNUM)
{
char buf[4];
if (target_read (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
buf, spufs_addr, sizeof buf) == sizeof buf)
regcache_raw_supply (regcache, SPU_PC_REGNUM, buf);
}
/* The GPRs are found in the "regs" spufs file. */
if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
{
char buf[16 * SPU_NUM_GPRS], annex[32];
int i;
xsnprintf (annex, sizeof annex, "%d/regs", spufs_fd);
if (target_read (ops_beneath, TARGET_OBJECT_SPU, annex,
buf, 0, sizeof buf) == sizeof buf)
for (i = 0; i < SPU_NUM_GPRS; i++)
regcache_raw_supply (regcache, i, buf + i*16);
}
}
/* Override the to_store_registers routine. */
static void
spu_store_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct target_ops *ops_beneath = find_target_beneath (ops);
int spufs_fd;
CORE_ADDR spufs_addr;
/* This version applies only if we're currently in spu_run. */
if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu)
{
while (ops_beneath && !ops_beneath->to_fetch_registers)
ops_beneath = find_target_beneath (ops_beneath);
gdb_assert (ops_beneath);
ops_beneath->to_store_registers (ops_beneath, regcache, regno);
return;
}
/* We must be stopped on a spu_run system call. */
if (!parse_spufs_run (inferior_ptid, &spufs_fd, &spufs_addr))
return;
/* The NPC register is found in PPC memory at SPUFS_ADDR. */
if (regno == -1 || regno == SPU_PC_REGNUM)
{
char buf[4];
regcache_raw_collect (regcache, SPU_PC_REGNUM, buf);
target_write (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
buf, spufs_addr, sizeof buf);
}
/* The GPRs are found in the "regs" spufs file. */
if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
{
char buf[16 * SPU_NUM_GPRS], annex[32];
int i;
for (i = 0; i < SPU_NUM_GPRS; i++)
regcache_raw_collect (regcache, i, buf + i*16);
xsnprintf (annex, sizeof annex, "%d/regs", spufs_fd);
target_write (ops_beneath, TARGET_OBJECT_SPU, annex,
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)
{
struct target_ops *ops_beneath = find_target_beneath (ops);
while (ops_beneath && !ops_beneath->to_xfer_partial)
ops_beneath = find_target_beneath (ops_beneath);
gdb_assert (ops_beneath);
/* Use the "mem" spufs file to access SPU local store. */
if (object == TARGET_OBJECT_MEMORY)
{
int fd = SPUADDR_SPU (offset);
CORE_ADDR addr = SPUADDR_ADDR (offset);
char mem_annex[32];
if (fd >= 0 && addr < SPU_LS_SIZE)
{
xsnprintf (mem_annex, sizeof mem_annex, "%d/mem", fd);
return ops_beneath->to_xfer_partial (ops_beneath, TARGET_OBJECT_SPU,
mem_annex, readbuf, writebuf,
addr, len);
}
}
return ops_beneath->to_xfer_partial (ops_beneath, object, annex,
readbuf, writebuf, offset, len);
}
/* Override the to_search_memory routine. */
static int
spu_search_memory (struct target_ops* ops,
CORE_ADDR start_addr, ULONGEST search_space_len,
const gdb_byte *pattern, ULONGEST pattern_len,
CORE_ADDR *found_addrp)
{
struct target_ops *ops_beneath = find_target_beneath (ops);
while (ops_beneath && !ops_beneath->to_search_memory)
ops_beneath = find_target_beneath (ops_beneath);
/* For SPU local store, always fall back to the simple method. Likewise
if we do not have any target-specific special implementation. */
if (!ops_beneath || SPUADDR_SPU (start_addr) >= 0)
return simple_search_memory (ops,
start_addr, search_space_len,
pattern, pattern_len, found_addrp);
return ops_beneath->to_search_memory (ops_beneath,
start_addr, search_space_len,
pattern, pattern_len, found_addrp);
}
/* Push and pop the SPU multi-architecture support target. */
static void
spu_multiarch_activate (void)
{
/* If GDB was configured without SPU architecture support,
we cannot install SPU multi-architecture support either. */
if (spu_gdbarch (-1) == NULL)
return;
push_target (&spu_ops);
/* Make sure the thread architecture is re-evaluated. */
registers_changed ();
}
static void
spu_multiarch_deactivate (void)
{
unpush_target (&spu_ops);
/* Make sure the thread architecture is re-evaluated. */
registers_changed ();
}
static void
spu_multiarch_inferior_created (struct target_ops *ops, int from_tty)
{
if (spu_standalone_p ())
spu_multiarch_activate ();
}
static void
spu_multiarch_solib_loaded (struct so_list *so)
{
if (!spu_standalone_p ())
if (so->abfd && bfd_get_arch (so->abfd) == bfd_arch_spu)
if (spu_nr_solib++ == 0)
spu_multiarch_activate ();
}
static void
spu_multiarch_solib_unloaded (struct so_list *so)
{
if (!spu_standalone_p ())
if (so->abfd && bfd_get_arch (so->abfd) == bfd_arch_spu)
if (--spu_nr_solib == 0)
spu_multiarch_deactivate ();
}
static void
spu_mourn_inferior (struct target_ops *ops)
{
struct target_ops *ops_beneath = find_target_beneath (ops);
while (ops_beneath && !ops_beneath->to_mourn_inferior)
ops_beneath = find_target_beneath (ops_beneath);
gdb_assert (ops_beneath);
ops_beneath->to_mourn_inferior (ops_beneath);
spu_multiarch_deactivate ();
}
/* Initialize the SPU multi-architecture support target. */
static void
init_spu_ops (void)
{
spu_ops.to_shortname = "spu";
spu_ops.to_longname = "SPU multi-architecture support.";
spu_ops.to_doc = "SPU multi-architecture support.";
spu_ops.to_mourn_inferior = spu_mourn_inferior;
spu_ops.to_fetch_registers = spu_fetch_registers;
spu_ops.to_store_registers = spu_store_registers;
spu_ops.to_xfer_partial = spu_xfer_partial;
spu_ops.to_search_memory = spu_search_memory;
spu_ops.to_region_ok_for_hw_watchpoint = spu_region_ok_for_hw_watchpoint;
spu_ops.to_thread_architecture = spu_thread_architecture;
spu_ops.to_stratum = arch_stratum;
spu_ops.to_magic = OPS_MAGIC;
}
void
_initialize_spu_multiarch (void)
{
/* Install ourselves on the target stack. */
init_spu_ops ();
add_target (&spu_ops);
/* Install observers to watch for SPU objects. */
observer_attach_inferior_created (spu_multiarch_inferior_created);
observer_attach_solib_loaded (spu_multiarch_solib_loaded);
observer_attach_solib_unloaded (spu_multiarch_solib_unloaded);
}

View file

@ -48,6 +48,9 @@
/* The tdep structure. */
struct gdbarch_tdep
{
/* The spufs ID identifying our address space. */
int id;
/* SPU-specific vector type. */
struct type *spu_builtin_type_vec128;
};
@ -330,34 +333,72 @@ spu_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
/* Address conversion. */
static int
spu_gdbarch_id (struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int id = tdep->id;
/* The objfile architecture of a standalone SPU executable does not
provide an SPU ID. Retrieve it from the the objfile's relocated
address range in this special case. */
if (id == -1
&& symfile_objfile && symfile_objfile->obfd
&& bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu
&& symfile_objfile->sections != symfile_objfile->sections_end)
id = SPUADDR_SPU (obj_section_addr (symfile_objfile->sections));
return id;
}
static ULONGEST
spu_lslr (int id)
{
gdb_byte buf[32];
char annex[32];
if (id == -1)
return SPU_LS_SIZE - 1;
xsnprintf (annex, sizeof annex, "%d/lslr", id);
memset (buf, 0, sizeof buf);
target_read (&current_target, TARGET_OBJECT_SPU, annex,
buf, 0, sizeof buf);
return strtoulst (buf, NULL, 16);
}
static void
spu_address_to_pointer (struct gdbarch *gdbarch,
struct type *type, gdb_byte *buf, CORE_ADDR addr)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order,
SPUADDR_ADDR (addr));
}
static CORE_ADDR
spu_pointer_to_address (struct gdbarch *gdbarch,
struct type *type, const gdb_byte *buf)
{
int id = spu_gdbarch_id (gdbarch);
ULONGEST lslr = spu_lslr (id);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST addr
= extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */
if (target_has_registers && target_has_stack && target_has_memory)
lslr = get_frame_register_unsigned (get_selected_frame (NULL),
SPU_LSLR_REGNUM);
return addr & lslr;
return addr? SPUADDR (id, addr & lslr) : 0;
}
static CORE_ADDR
spu_integer_to_address (struct gdbarch *gdbarch,
struct type *type, const gdb_byte *buf)
{
int id = spu_gdbarch_id (gdbarch);
ULONGEST lslr = spu_lslr (id);
ULONGEST addr = unpack_long (type, buf);
ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */
if (target_has_registers && target_has_stack && target_has_memory)
lslr = get_frame_register_unsigned (get_selected_frame (NULL),
SPU_LSLR_REGNUM);
return addr & lslr;
return SPUADDR (id, addr & lslr);
}
@ -851,9 +892,11 @@ spu_frame_unwind_cache (struct frame_info *this_frame,
void **this_prologue_cache)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct spu_unwind_cache *info;
struct spu_prologue_data data;
CORE_ADDR id = tdep->id;
gdb_byte buf[16];
if (*this_prologue_cache)
@ -886,6 +929,7 @@ spu_frame_unwind_cache (struct frame_info *this_frame,
/* Determine CFA via unwound CFA_REG plus CFA_OFFSET. */
get_frame_register (this_frame, data.cfa_reg, buf);
cfa = extract_unsigned_integer (buf, 4, byte_order) + data.cfa_offset;
cfa = SPUADDR (id, cfa);
/* Call-saved register slots. */
for (i = 0; i < SPU_NUM_GPRS; i++)
@ -908,7 +952,8 @@ spu_frame_unwind_cache (struct frame_info *this_frame,
/* Get the backchain. */
reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
status = safe_read_memory_integer (reg, 4, byte_order, &backchain);
status = safe_read_memory_integer (SPUADDR (id, reg), 4, byte_order,
&backchain);
/* A zero backchain terminates the frame chain. Also, sanity
check against the local store size limit. */
@ -916,11 +961,11 @@ spu_frame_unwind_cache (struct frame_info *this_frame,
{
/* Assume the link register is saved into its slot. */
if (backchain + 16 < SPU_LS_SIZE)
info->saved_regs[SPU_LR_REGNUM].addr = backchain + 16;
info->saved_regs[SPU_LR_REGNUM].addr = SPUADDR (id, backchain + 16);
/* Frame bases. */
info->frame_base = backchain;
info->local_base = reg;
info->frame_base = SPUADDR (id, backchain);
info->local_base = SPUADDR (id, reg);
}
}
@ -929,7 +974,8 @@ spu_frame_unwind_cache (struct frame_info *this_frame,
return info;
/* The previous SP is equal to the CFA. */
trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, info->frame_base);
trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM,
SPUADDR_ADDR (info->frame_base));
/* Read full contents of the unwound link register in order to
be able to determine the return address. */
@ -1007,24 +1053,28 @@ static const struct frame_base spu_frame_base = {
static CORE_ADDR
spu_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
/* Mask off interrupt enable bit. */
return pc & -4;
return SPUADDR (tdep->id, pc & -4);
}
static CORE_ADDR
spu_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
return SPUADDR (tdep->id, sp);
}
static CORE_ADDR
spu_read_pc (struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
ULONGEST pc;
regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &pc);
/* Mask off interrupt enable bit. */
return pc & -4;
return SPUADDR (tdep->id, pc & -4);
}
static void
@ -1034,7 +1084,7 @@ spu_write_pc (struct regcache *regcache, CORE_ADDR pc)
ULONGEST old_pc;
regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &old_pc);
regcache_cooked_write_unsigned (regcache, SPU_PC_REGNUM,
(pc & -4) | (old_pc & 3));
(SPUADDR_ADDR (pc) & -4) | (old_pc & 3));
}
@ -1146,7 +1196,7 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
/* Set the return address. */
memset (buf, 0, sizeof buf);
store_unsigned_integer (buf, 4, byte_order, bp_addr);
store_unsigned_integer (buf, 4, byte_order, SPUADDR_ADDR (bp_addr));
regcache_cooked_write (regcache, SPU_LR_REGNUM, buf);
/* If STRUCT_RETURN is true, then the struct return address (in
@ -1155,7 +1205,7 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
if (struct_return)
{
memset (buf, 0, sizeof buf);
store_unsigned_integer (buf, 4, byte_order, struct_addr);
store_unsigned_integer (buf, 4, byte_order, SPUADDR_ADDR (struct_addr));
regcache_cooked_write (regcache, regnum++, buf);
}
@ -1233,9 +1283,10 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
static struct frame_id
spu_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR pc = get_frame_register_unsigned (this_frame, SPU_PC_REGNUM);
CORE_ADDR sp = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
return frame_id_build (sp, pc & -4);
return frame_id_build (SPUADDR (tdep->id, sp), SPUADDR (tdep->id, pc & -4));
}
/* Function return value access. */
@ -1317,18 +1368,18 @@ spu_software_single_step (struct frame_info *frame)
instruction is a PPE-assisted call, in which case it is at PC + 8.
Wrap around LS limit to be on the safe side. */
if ((insn & 0xffffff00) == 0x00002100)
next_pc = (pc + 8) & (SPU_LS_SIZE - 1);
next_pc = (SPUADDR_ADDR (pc) + 8) & (SPU_LS_SIZE - 1);
else
next_pc = (pc + 4) & (SPU_LS_SIZE - 1);
next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1);
insert_single_step_breakpoint (gdbarch, next_pc);
insert_single_step_breakpoint (gdbarch, SPUADDR (SPUADDR_SPU (pc), next_pc));
if (is_branch (insn, &offset, &reg))
{
CORE_ADDR target = offset;
if (reg == SPU_PC_REGNUM)
target += pc;
target += SPUADDR_ADDR (pc);
else if (reg != -1)
{
get_frame_register_bytes (frame, reg, 0, 4, buf);
@ -1337,7 +1388,8 @@ spu_software_single_step (struct frame_info *frame)
target = target & (SPU_LS_SIZE - 1);
if (target != next_pc)
insert_single_step_breakpoint (gdbarch, target);
insert_single_step_breakpoint (gdbarch,
SPUADDR (SPUADDR_SPU (pc), target));
}
return 1;
@ -1350,6 +1402,7 @@ static int
spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
gdb_byte buf[4];
CORE_ADDR jb_addr;
@ -1357,14 +1410,46 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
/* Jump buffer is pointed to by the argument register $r3. */
get_frame_register_bytes (frame, SPU_ARG1_REGNUM, 0, 4, buf);
jb_addr = extract_unsigned_integer (buf, 4, byte_order);
if (target_read_memory (jb_addr, buf, 4))
if (target_read_memory (SPUADDR (tdep->id, jb_addr), buf, 4))
return 0;
*pc = extract_unsigned_integer (buf, 4, byte_order);
*pc = SPUADDR (tdep->id, *pc);
return 1;
}
/* Disassembler. */
struct spu_dis_asm_data
{
struct gdbarch *gdbarch;
int id;
};
static void
spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
{
struct spu_dis_asm_data *data = info->application_data;
print_address (data->gdbarch, SPUADDR (data->id, addr), info->stream);
}
static int
gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
{
/* The opcodes disassembler does 18-bit address arithmetic. Make sure the
SPU ID encoded in the high bits is added back when we call print_address. */
struct disassemble_info spu_info = *info;
struct spu_dis_asm_data data;
data.gdbarch = info->application_data;
data.id = SPUADDR_SPU (memaddr);
spu_info.application_data = &data;
spu_info.print_address_func = spu_dis_asm_print_address;
return print_insn_spu (memaddr, &spu_info);
}
/* Target overlays for the SPU overlay manager.
See the documentation of simple_overlay_update for how the
@ -1489,7 +1574,7 @@ spu_overlay_update_osect (struct obj_section *osect)
enum bfd_endian byte_order = bfd_big_endian (osect->objfile->obfd)?
BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
struct spu_overlay_table *ovly_table;
CORE_ADDR val;
CORE_ADDR id, val;
ovly_table = spu_get_overlay_table (osect->objfile);
if (!ovly_table)
@ -1499,7 +1584,9 @@ spu_overlay_update_osect (struct obj_section *osect)
if (ovly_table->mapped_ptr == 0)
return;
val = read_memory_unsigned_integer (ovly_table->mapped_ptr, 4, byte_order);
id = SPUADDR_SPU (obj_section_addr (osect));
val = read_memory_unsigned_integer (SPUADDR (id, ovly_table->mapped_ptr),
4, byte_order);
osect->ovly_mapped = (val == ovly_table->mapped_val);
}
@ -2137,22 +2224,37 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int id = -1;
/* Find a candidate among the list of pre-declared architectures. */
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
/* Which spufs ID was requested as address space? */
if (info.tdep_info)
id = *(int *)info.tdep_info;
/* For objfile architectures of SPU solibs, decode the ID from the name.
This assumes the filename convention employed by solib-spu.c. */
else if (info.abfd)
{
char *name = strrchr (info.abfd->filename, '@');
if (name)
sscanf (name, "@0x%*x <%d>", &id);
}
/* Is is for us? */
if (info.bfd_arch_info->mach != bfd_mach_spu)
return NULL;
/* Find a candidate among extant architectures. */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
arches = gdbarch_list_lookup_by_info (arches->next, &info))
{
tdep = gdbarch_tdep (arches->gdbarch);
if (tdep && tdep->id == id)
return arches->gdbarch;
}
/* Yes, create a new architecture. */
/* None found, so create a new architecture. */
tdep = XCALLOC (1, struct gdbarch_tdep);
tdep->id = id;
gdbarch = gdbarch_alloc (&info, tdep);
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_spu);
set_gdbarch_print_insn (gdbarch, gdb_print_insn_spu);
/* Registers. */
set_gdbarch_num_regs (gdbarch, SPU_NUM_REGS);
@ -2184,6 +2286,7 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
/* Address conversion. */
set_gdbarch_address_to_pointer (gdbarch, spu_address_to_pointer);
set_gdbarch_pointer_to_address (gdbarch, spu_pointer_to_address);
set_gdbarch_integer_to_address (gdbarch, spu_integer_to_address);

View file

@ -50,4 +50,12 @@ enum spu_regnum
/* Local store. */
#define SPU_LS_SIZE 0x40000
/* Address conversions. */
#define SPUADDR(spu, addr) \
((spu) != -1? (ULONGEST)1 << 63 | (ULONGEST)(spu) << 32 | (addr) : (addr))
#define SPUADDR_SPU(addr) \
(((addr) & (ULONGEST)1 << 63)? (ULONGEST)(addr) >> 32 & 0x7fffffff : -1)
#define SPUADDR_ADDR(addr) \
(((addr) & (ULONGEST)1 << 63)? (ULONGEST)(addr) & 0xffffffff : (addr))
#endif

View file

@ -2298,7 +2298,8 @@ target_require_runnable (void)
/* Do not worry about thread_stratum targets that can not
create inferiors. Assume they will be pushed again if
necessary, and continue to the process_stratum. */
if (t->to_stratum == thread_stratum)
if (t->to_stratum == thread_stratum
|| t->to_stratum == arch_stratum)
continue;
error (_("\

View file

@ -65,7 +65,8 @@ enum strata
core_stratum, /* Core dump files */
process_stratum, /* Executing processes */
thread_stratum, /* Executing threads */
record_stratum /* Support record debugging */
record_stratum, /* Support record debugging */
arch_stratum /* Architecture overrides */
};
enum thread_control_capabilities

View file

@ -1,3 +1,7 @@
2009-07-31 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* gdb.xml/tdesc-regs.exp: Skip for SPU targets.
2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.base/float.exp: Handle VFP registers.

View file

@ -39,6 +39,16 @@ switch -glob -- [istarget] {
set regdir "rs6000/"
set core-regs {power-core.xml}
}
"spu*-*-*" {
# This may be either the spu-linux-nat target, or the Cell/B.E.
# multi-architecture debugger in SPU standalone executable mode.
# We do not support XML register sets on SPU in either case.
# However, the multi-arch debugger will accept XML registers sets
# (on the PowerPC side), hence the test below would fail.
# Simply return unconditionally here.
unsupported "register tests"
return 0
}
}
# If no core registers were specified, assume this target does not