5627 lines
180 KiB
Diff
5627 lines
180 KiB
Diff
--- gdb/Makefile.in
|
||
+++ gdb/Makefile.in
|
||
@@ -502,7 +502,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 \
|
||
@@ -1342,7 +1342,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 \
|
||
+ 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 \
|
||
--- gdb/arch-utils.c
|
||
+++ gdb/arch-utils.c
|
||
@@ -326,15 +326,24 @@ set_endian (char *ignore_args, int from_
|
||
}
|
||
|
||
/* Given SELECTED, a currently selected BFD architecture, and
|
||
- FROM_TARGET, a BFD architecture reported by the target description,
|
||
- return what architecture to use. Either may be NULL; if both are
|
||
- specified, we use the more specific. If the two are obviously
|
||
- incompatible, warn the user. */
|
||
+ TARGET_DESC, the current target description, return what
|
||
+ architecture to use.
|
||
+
|
||
+ SELECTED may be NULL, in which case we return the architecture
|
||
+ associated with TARGET_DESC. If SELECTED specifies a variant
|
||
+ of the architecture associtated with TARGET_DESC, return the
|
||
+ more specific of the two.
|
||
+
|
||
+ If SELECTED is a different architecture, but it is accepted as
|
||
+ compatible by the target, we can use the target architecture.
|
||
+
|
||
+ If SELECTED is obviously incompatible, warn the user. */
|
||
|
||
static const struct bfd_arch_info *
|
||
-choose_architecture_for_target (const struct bfd_arch_info *selected,
|
||
- const struct bfd_arch_info *from_target)
|
||
+choose_architecture_for_target (const struct target_desc *target_desc,
|
||
+ const struct bfd_arch_info *selected)
|
||
{
|
||
+ const struct bfd_arch_info *from_target = tdesc_architecture (target_desc);
|
||
const struct bfd_arch_info *compat1, *compat2;
|
||
|
||
if (selected == NULL)
|
||
@@ -364,6 +373,11 @@ choose_architecture_for_target (const st
|
||
|
||
if (compat1 == NULL && compat2 == NULL)
|
||
{
|
||
+ /* BFD considers the architectures incompatible. Check our target
|
||
+ description whether it accepts SELECTED as compatible anyway. */
|
||
+ if (tdesc_compatible_p (target_desc, selected))
|
||
+ return from_target;
|
||
+
|
||
warning (_("Selected architecture %s is not compatible "
|
||
"with reported target architecture %s"),
|
||
selected->printable_name, from_target->printable_name);
|
||
@@ -692,7 +706,7 @@ gdbarch_info_fill (struct gdbarch_info *
|
||
/* From the target. */
|
||
if (info->target_desc != NULL)
|
||
info->bfd_arch_info = choose_architecture_for_target
|
||
- (info->bfd_arch_info, tdesc_architecture (info->target_desc));
|
||
+ (info->target_desc, info->bfd_arch_info);
|
||
/* From the default. */
|
||
if (info->bfd_arch_info == NULL)
|
||
info->bfd_arch_info = default_bfd_arch;
|
||
@@ -720,6 +734,27 @@ gdbarch_info_fill (struct gdbarch_info *
|
||
gdb_assert (info->bfd_arch_info != NULL);
|
||
}
|
||
|
||
+
|
||
+/* restore_current_gdbarch() will be used by the cleanup machinery
|
||
+ to restore the current_gdbarch value saved in a call to
|
||
+ save_current_gdbarch(). */
|
||
+
|
||
+static void
|
||
+restore_current_gdbarch (void *arg)
|
||
+{
|
||
+ current_gdbarch = arg;
|
||
+}
|
||
+
|
||
+/* Save the value of current so that it may be restored by a
|
||
+ later call to do_cleanups(). Returns the struct cleanup pointer
|
||
+ needed for later doing the cleanup. */
|
||
+
|
||
+struct cleanup *
|
||
+save_current_gdbarch (void)
|
||
+{
|
||
+ return make_cleanup (restore_current_gdbarch, current_gdbarch);
|
||
+}
|
||
+
|
||
/* */
|
||
|
||
extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
|
||
--- gdb/arch-utils.h
|
||
+++ gdb/arch-utils.h
|
||
@@ -139,4 +139,9 @@ extern void gdbarch_info_fill (struct gd
|
||
|
||
extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
|
||
|
||
+/* Save value of current_gdbarch so that it may be restored by
|
||
+ a later call to do_cleanups(). Returns the struct cleanup
|
||
+ pointer needed for later doing the cleanup. */
|
||
+struct cleanup *save_current_gdbarch (void);
|
||
+
|
||
#endif
|
||
--- gdb/avr-tdep.c
|
||
+++ gdb/avr-tdep.c
|
||
@@ -278,7 +278,8 @@ avr_convert_saddr_to_raw (CORE_ADDR x)
|
||
/* Convert from address to pointer and vice-versa. */
|
||
|
||
static void
|
||
-avr_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+avr_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
/* Is it a code address? */
|
||
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
|
||
@@ -296,7 +297,8 @@ avr_address_to_pointer (struct type *typ
|
||
}
|
||
|
||
static CORE_ADDR
|
||
-avr_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+avr_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
{
|
||
CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
|
||
|
||
--- gdb/breakpoint.c
|
||
+++ gdb/breakpoint.c
|
||
@@ -1134,7 +1134,7 @@ Note: automatically using hardware break
|
||
bpt->overlay_target_info = bpt->target_info;
|
||
bpt->overlay_target_info.placed_address = addr;
|
||
val = target_insert_breakpoint (&bpt->overlay_target_info);
|
||
- if (val != 0)
|
||
+ if (val > 0)
|
||
fprintf_unfiltered (tmp_error_stream,
|
||
"Overlay breakpoint %d failed: in ROM?",
|
||
bpt->owner->number);
|
||
@@ -1157,6 +1157,14 @@ Note: automatically using hardware break
|
||
}
|
||
}
|
||
|
||
+ if (val < 0)
|
||
+ {
|
||
+ /* The target could not insert the breakpoint right away due
|
||
+ to a temporary issue. No error, but do not mark the bp
|
||
+ as 'inserted'. */
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
if (val)
|
||
{
|
||
/* Can't set the breakpoint. */
|
||
@@ -1626,6 +1634,14 @@ remove_breakpoint (struct bp_location *b
|
||
}
|
||
}
|
||
|
||
+ if (val < 0)
|
||
+ {
|
||
+ /* The target could not remove the breakpoint right away due
|
||
+ to a temporary issue. No error, but keep the bp marked
|
||
+ as 'inserted'. */
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
/* In some cases, we might not be able to remove a breakpoint
|
||
in a shared library that has already been removed, but we
|
||
have not yet processed the shlib unload event. */
|
||
@@ -7553,6 +7569,37 @@ breakpoint_re_set (void)
|
||
|
||
create_overlay_event_breakpoint ("_ovly_debug_event");
|
||
}
|
||
+
|
||
+/* Update breakpoint location list after an object file was relocated. */
|
||
+void
|
||
+breakpoint_relocate (struct objfile *objfile, struct section_offsets *delta)
|
||
+{
|
||
+ struct bp_location *b;
|
||
+ struct obj_section *s;
|
||
+
|
||
+ /* Update the breakpoint addresses so that breakpoint_re_set has a chance
|
||
+ to identify the previous locations (to carry over enabled state). */
|
||
+ ALL_BP_LOCATIONS (b)
|
||
+ {
|
||
+ if (b->inserted || b->loc_type == bp_loc_other)
|
||
+ continue;
|
||
+
|
||
+ ALL_OBJFILE_OSECTIONS (objfile, s)
|
||
+ {
|
||
+ CORE_ADDR offset = ANOFFSET (delta, s->the_bfd_section->index);
|
||
+
|
||
+ if (b->address >= obj_section_addr (s) - offset
|
||
+ && b->address < obj_section_endaddr (s) - offset)
|
||
+ {
|
||
+ b->address += offset;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Now reset all breakpoints. */
|
||
+ breakpoint_re_set ();
|
||
+}
|
||
|
||
/* Reset the thread number of this breakpoint:
|
||
|
||
--- gdb/breakpoint.h
|
||
+++ gdb/breakpoint.h
|
||
@@ -670,6 +670,8 @@ extern int breakpoint_thread_match (CORE
|
||
|
||
extern void until_break_command (char *, int, int);
|
||
|
||
+extern void breakpoint_relocate (struct objfile *, struct section_offsets *);
|
||
+
|
||
extern void breakpoint_re_set (void);
|
||
|
||
extern void breakpoint_re_set_thread (struct breakpoint *);
|
||
--- gdb/cli/cli-dump.c
|
||
+++ gdb/cli/cli-dump.c
|
||
@@ -428,7 +428,7 @@ add_dump_command (char *name, void (*fun
|
||
|
||
/* Opaque data for restore_section_callback. */
|
||
struct callback_data {
|
||
- long load_offset;
|
||
+ CORE_ADDR load_offset;
|
||
CORE_ADDR load_start;
|
||
CORE_ADDR load_end;
|
||
};
|
||
@@ -533,8 +533,8 @@ restore_binary_file (char *filename, str
|
||
printf_filtered
|
||
("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
|
||
filename,
|
||
- (unsigned long) data->load_start + data->load_offset,
|
||
- (unsigned long) data->load_start + data->load_offset + len);
|
||
+ (unsigned long) (data->load_start + data->load_offset),
|
||
+ (unsigned long) (data->load_start + data->load_offset + len));
|
||
|
||
/* Now set the file pos to the requested load start pos. */
|
||
if (fseek (file, data->load_start, SEEK_SET) != 0)
|
||
@@ -584,7 +584,7 @@ restore_command (char *args, int from_tt
|
||
/* Parse offset (optional). */
|
||
if (args != NULL && *args != '\0')
|
||
data.load_offset =
|
||
- parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
|
||
+ parse_and_eval_address (scan_expression_with_cleanup (&args, NULL));
|
||
if (args != NULL && *args != '\0')
|
||
{
|
||
/* Parse start address (optional). */
|
||
--- gdb/configure.tgt
|
||
+++ gdb/configure.tgt
|
||
@@ -354,7 +354,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
|
||
;;
|
||
--- gdb/corelow.c
|
||
+++ gdb/corelow.c
|
||
@@ -560,6 +560,33 @@ core_files_info (struct target_ops *t)
|
||
print_section_info (t, core_bfd);
|
||
}
|
||
|
||
+struct spuid_list
|
||
+{
|
||
+ gdb_byte *buf;
|
||
+ ULONGEST offset;
|
||
+ LONGEST len;
|
||
+ ULONGEST pos;
|
||
+ ULONGEST written;
|
||
+};
|
||
+
|
||
+static void
|
||
+add_to_spuid_list (bfd *abfd, asection *asect, void *list_p)
|
||
+{
|
||
+ struct spuid_list *list = list_p;
|
||
+ int fd, pos = 0;
|
||
+
|
||
+ sscanf (bfd_section_name (abfd, asect), "SPU/%d/regs%n", &fd, &pos);
|
||
+ if (pos == 0)
|
||
+ return;
|
||
+
|
||
+ if (list->pos >= list->offset && list->pos + 4 <= list->offset + list->len)
|
||
+ {
|
||
+ store_unsigned_integer (list->buf + list->pos - list->offset, 4, fd);
|
||
+ list->written += 4;
|
||
+ }
|
||
+ list->pos += 4;
|
||
+}
|
||
+
|
||
static LONGEST
|
||
core_xfer_partial (struct target_ops *ops, enum target_object object,
|
||
const char *annex, gdb_byte *readbuf,
|
||
@@ -652,6 +679,53 @@ core_xfer_partial (struct target_ops *op
|
||
}
|
||
/* FALL THROUGH */
|
||
|
||
+ case TARGET_OBJECT_SPU:
|
||
+ if (readbuf && annex)
|
||
+ {
|
||
+ /* When the SPU contexts are stored in core file, BFD
|
||
+ represents this with a fake section called "SPU/<annex>". */
|
||
+
|
||
+ struct bfd_section *section;
|
||
+ bfd_size_type size;
|
||
+ char *contents;
|
||
+
|
||
+ char sectionstr[100];
|
||
+ xsnprintf (sectionstr, sizeof sectionstr, "SPU/%s", annex);
|
||
+
|
||
+ section = bfd_get_section_by_name (core_bfd, sectionstr);
|
||
+ if (section == NULL)
|
||
+ return -1;
|
||
+
|
||
+ size = bfd_section_size (core_bfd, section);
|
||
+ if (offset >= size)
|
||
+ return 0;
|
||
+ size -= offset;
|
||
+ if (size > len)
|
||
+ size = len;
|
||
+ if (size > 0
|
||
+ && !bfd_get_section_contents (core_bfd, section, readbuf,
|
||
+ (file_ptr) offset, size))
|
||
+ {
|
||
+ warning (_("Couldn't read SPU section in core file."));
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ return size;
|
||
+ }
|
||
+ else if (readbuf)
|
||
+ {
|
||
+ /* NULL annex requests list of all present spuids. */
|
||
+ struct spuid_list list;
|
||
+ list.buf = readbuf;
|
||
+ list.offset = offset;
|
||
+ list.len = len;
|
||
+ list.pos = 0;
|
||
+ list.written = 0;
|
||
+ bfd_map_over_sections (core_bfd, add_to_spuid_list, &list);
|
||
+ return list.written;
|
||
+ }
|
||
+ return -1;
|
||
+
|
||
default:
|
||
if (ops->beneath != NULL)
|
||
return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
|
||
@@ -691,8 +765,8 @@ core_file_thread_alive (ptid_t tid)
|
||
static const struct target_desc *
|
||
core_read_description (struct target_ops *target)
|
||
{
|
||
- if (gdbarch_core_read_description_p (current_gdbarch))
|
||
- return gdbarch_core_read_description (current_gdbarch, target, core_bfd);
|
||
+ if (core_gdbarch && gdbarch_core_read_description_p (core_gdbarch))
|
||
+ return gdbarch_core_read_description (core_gdbarch, target, core_bfd);
|
||
|
||
return NULL;
|
||
}
|
||
--- gdb/doc/gdb.texinfo
|
||
+++ gdb/doc/gdb.texinfo
|
||
@@ -16910,6 +16910,33 @@ and local store addresses and transfer s
|
||
|
||
@end table
|
||
|
||
+When @value{GDBN} is debugging a combined PowerPC/SPU application
|
||
+on the Cell Broadband Engine, it provides in addition the following
|
||
+special commands:
|
||
+
|
||
+@table @code
|
||
+@item set spu stop-on-load @var{arg}
|
||
+@kindex set spu
|
||
+Set whether to stop for new SPE threads. When set to @code{on}, @value{GDBN}
|
||
+will give control to the user when a new SPE thread enters its @code{main}
|
||
+function. The default is @code{off}.
|
||
+
|
||
+@item show spu stop-on-load
|
||
+@kindex show spu
|
||
+Show whether to stop for new SPE threads.
|
||
+
|
||
+@item set spu auto-flush-cache @var{arg}
|
||
+Set whether to automatically flush the software-managed cache. When set to
|
||
+@code{on}, @value{GDBN} will automatically cause the SPE software-managed
|
||
+cache to be flushed whenever SPE execution stops. This provides a consistent
|
||
+view of PowerPC memory that is accessed via the cache. If an application
|
||
+does not use the software-managed cache, this option has no effect.
|
||
+
|
||
+@item show spu auto-flush-cache
|
||
+Show whether to automatically flush the software-managed cache.
|
||
+
|
||
+@end table
|
||
+
|
||
@node PowerPC
|
||
@subsection PowerPC
|
||
@cindex PowerPC architecture
|
||
@@ -29271,6 +29298,7 @@ are explained further below.
|
||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||
<target version="1.0">
|
||
@r{[}@var{architecture}@r{]}
|
||
+ @r{[}@var{compatible}@dots{}@r{]}
|
||
@r{[}@var{feature}@dots{}@r{]}
|
||
</target>
|
||
@end smallexample
|
||
@@ -29322,9 +29350,33 @@ An @samp{<architecture>} element has thi
|
||
<architecture>@var{arch}</architecture>
|
||
@end smallexample
|
||
|
||
-@var{arch} is an architecture name from the same selection
|
||
-accepted by @code{set architecture} (@pxref{Targets, ,Specifying a
|
||
-Debugging Target}).
|
||
+@var{arch} is one of the architectures from the set accepted by
|
||
+@code{set architecture} (@pxref{Targets, ,Specifying a Debugging Target}).
|
||
+
|
||
+@subsection Compatible Architecture
|
||
+@cindex <compatible>
|
||
+
|
||
+A @samp{<compatible>} element has this form:
|
||
+
|
||
+@smallexample
|
||
+ <compatible>@var{arch}</compatible>
|
||
+@end smallexample
|
||
+
|
||
+@var{arch} is one of the architectures from the set accepted by
|
||
+@code{set architecture} (@pxref{Targets, ,Specifying a Debugging Target}).
|
||
+
|
||
+A @samp{<compatible>} element is used to specify that the target
|
||
+is able to run binaries in some other than the main target architecture
|
||
+given by the @samp{<architecture>} element. For example, on the
|
||
+Cell Broadband Engine, the main architecture is @code{powerpc:common}
|
||
+or @code{powerpc:common64}, but the system is able to run binaries
|
||
+in the @code{spu} architecture as well. The way to describe this
|
||
+capability with @samp{<compatible>} is as follows:
|
||
+
|
||
+@smallexample
|
||
+ <architecture>@code{powerpc:common}</architecture>
|
||
+ <compatible>@code{spu}</compatible>
|
||
+@end smallexample
|
||
|
||
@subsection Features
|
||
@cindex <feature>
|
||
--- gdb/features/Makefile
|
||
+++ gdb/features/Makefile
|
||
@@ -34,7 +34,7 @@
|
||
WHICH = arm-with-iwmmxt mips-linux mips64-linux \
|
||
rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
|
||
rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
|
||
- rs6000/powerpc-vsx64l
|
||
+ rs6000/powerpc-vsx64l rs6000/powerpc-cell32l rs6000/powerpc-cell64l
|
||
|
||
# Record which registers should be sent to GDB by default after stop.
|
||
arm-with-iwmmxt-expedite = r11,sp,pc
|
||
@@ -42,6 +42,7 @@ mips-linux-expedite = r29,pc
|
||
mips64-linux-expedite = r29,pc
|
||
rs6000/powerpc-32l-expedite = r1,pc
|
||
rs6000/powerpc-altivec32l-expedite = r1,pc
|
||
+rs6000/powerpc-cell32l-expedite = r1,pc,r0,orig_r3,r4
|
||
rs6000/powerpc-vsx32l-expedite = r1,pc
|
||
rs6000/powerpc-isa205-32l-expedite = r1,pc
|
||
rs6000/powerpc-isa205-altivec32l-expedite = r1,pc
|
||
@@ -49,6 +50,7 @@ rs6000/powerpc-isa205-vsx32l-expedite =
|
||
rs6000/powerpc-e500l-expedite = r1,pc
|
||
rs6000/powerpc-64l-expedite = r1,pc
|
||
rs6000/powerpc-altivec64l-expedite = r1,pc
|
||
+rs6000/powerpc-cell64l-expedite = r1,pc,r0,orig_r3,r4
|
||
rs6000/powerpc-vsx64l-expedite = r1,pc
|
||
rs6000/powerpc-isa205-64l-expedite = r1,pc
|
||
rs6000/powerpc-isa205-altivec64l-expedite = r1,pc
|
||
--- gdb/features/rs6000/powerpc-cell32l.c
|
||
+++ gdb/features/rs6000/powerpc-cell32l.c
|
||
@@ -0,0 +1,170 @@
|
||
+/* THIS FILE IS GENERATED. Original: powerpc-cell32l.xml */
|
||
+
|
||
+#include "defs.h"
|
||
+#include "gdbtypes.h"
|
||
+#include "target-descriptions.h"
|
||
+
|
||
+struct target_desc *tdesc_powerpc_cell32l;
|
||
+static void
|
||
+initialize_tdesc_powerpc_cell32l (void)
|
||
+{
|
||
+ struct target_desc *result = allocate_target_description ();
|
||
+ struct tdesc_feature *feature;
|
||
+ struct type *field_type, *type;
|
||
+
|
||
+ set_tdesc_architecture (result, bfd_scan_arch ("powerpc:common"));
|
||
+
|
||
+ tdesc_add_compatible (result, bfd_scan_arch ("spu:256K"));
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.core");
|
||
+ tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "pc", 64, 1, NULL, 32, "code_ptr");
|
||
+ tdesc_create_reg (feature, "msr", 65, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "cr", 66, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "lr", 67, 1, NULL, 32, "code_ptr");
|
||
+ tdesc_create_reg (feature, "ctr", 68, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "xer", 69, 1, NULL, 32, "uint32");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.fpu");
|
||
+ tdesc_create_reg (feature, "f0", 32, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f1", 33, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f2", 34, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f3", 35, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f4", 36, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f5", 37, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f6", 38, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f7", 39, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f8", 40, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f9", 41, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f10", 42, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f11", 43, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f12", 44, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f13", 45, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f14", 46, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f15", 47, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f16", 48, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f17", 49, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f18", 50, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f19", 51, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f20", 52, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f21", 53, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f22", 54, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f23", 55, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f24", 56, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f25", 57, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f26", 58, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f27", 59, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f28", 60, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f29", 61, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f30", 62, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f31", 63, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "fpscr", 70, 1, "float", 32, "int");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux");
|
||
+ tdesc_create_reg (feature, "orig_r3", 71, 1, NULL, 32, "int");
|
||
+ tdesc_create_reg (feature, "trap", 72, 1, NULL, 32, "int");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.altivec");
|
||
+ field_type = tdesc_named_type (feature, "ieee_single");
|
||
+ type = init_vector_type (field_type, 4);
|
||
+ TYPE_NAME (type) = xstrdup ("v4f");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int32");
|
||
+ type = init_vector_type (field_type, 4);
|
||
+ TYPE_NAME (type) = xstrdup ("v4i32");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int16");
|
||
+ type = init_vector_type (field_type, 8);
|
||
+ TYPE_NAME (type) = xstrdup ("v8i16");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int8");
|
||
+ type = init_vector_type (field_type, 16);
|
||
+ TYPE_NAME (type) = xstrdup ("v16i8");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ type = init_composite_type (NULL, TYPE_CODE_UNION);
|
||
+ TYPE_NAME (type) = xstrdup ("vec128");
|
||
+ field_type = tdesc_named_type (feature, "uint128");
|
||
+ append_composite_type_field (type, xstrdup ("uint128"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v4f");
|
||
+ append_composite_type_field (type, xstrdup ("v4_float"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v4i32");
|
||
+ append_composite_type_field (type, xstrdup ("v4_int32"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v8i16");
|
||
+ append_composite_type_field (type, xstrdup ("v8_int16"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v16i8");
|
||
+ append_composite_type_field (type, xstrdup ("v16_int8"), field_type);
|
||
+ TYPE_VECTOR (type) = 1;
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ tdesc_create_reg (feature, "vr0", 73, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr1", 74, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr2", 75, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr3", 76, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr4", 77, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr5", 78, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr6", 79, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr7", 80, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr8", 81, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr9", 82, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr10", 83, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr11", 84, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr12", 85, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr13", 86, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr14", 87, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr15", 88, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr16", 89, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr17", 90, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr18", 91, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr19", 92, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr20", 93, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr21", 94, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr22", 95, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr23", 96, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr24", 97, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr25", 98, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr26", 99, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr27", 100, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr28", 101, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr29", 102, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr30", 103, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr31", 104, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vscr", 105, 1, "vector", 32, "int");
|
||
+ tdesc_create_reg (feature, "vrsave", 106, 1, "vector", 32, "int");
|
||
+
|
||
+ tdesc_powerpc_cell32l = result;
|
||
+}
|
||
--- gdb/features/rs6000/powerpc-cell32l.xml
|
||
+++ gdb/features/rs6000/powerpc-cell32l.xml
|
||
@@ -0,0 +1,19 @@
|
||
+<?xml version="1.0"?>
|
||
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
|
||
+
|
||
+ Copying and distribution of this file, with or without modification,
|
||
+ are permitted in any medium without royalty provided the copyright
|
||
+ notice and this notice are preserved. -->
|
||
+
|
||
+<!-- Cell/B.E. architecture. Identical to the PowerPC 32-bit Linux UISA,
|
||
+ but adds support for the SPU as compatible architecture. -->
|
||
+
|
||
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||
+<target>
|
||
+ <architecture>powerpc:common</architecture>
|
||
+ <compatible>spu</compatible>
|
||
+ <xi:include href="power-core.xml"/>
|
||
+ <xi:include href="power-fpu.xml"/>
|
||
+ <xi:include href="power-linux.xml"/>
|
||
+ <xi:include href="power-altivec.xml"/>
|
||
+</target>
|
||
--- gdb/features/rs6000/powerpc-cell64l.c
|
||
+++ gdb/features/rs6000/powerpc-cell64l.c
|
||
@@ -0,0 +1,170 @@
|
||
+/* THIS FILE IS GENERATED. Original: powerpc-cell64l.xml */
|
||
+
|
||
+#include "defs.h"
|
||
+#include "gdbtypes.h"
|
||
+#include "target-descriptions.h"
|
||
+
|
||
+struct target_desc *tdesc_powerpc_cell64l;
|
||
+static void
|
||
+initialize_tdesc_powerpc_cell64l (void)
|
||
+{
|
||
+ struct target_desc *result = allocate_target_description ();
|
||
+ struct tdesc_feature *feature;
|
||
+ struct type *field_type, *type;
|
||
+
|
||
+ set_tdesc_architecture (result, bfd_scan_arch ("powerpc:common64"));
|
||
+
|
||
+ tdesc_add_compatible (result, bfd_scan_arch ("spu:256K"));
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.core");
|
||
+ tdesc_create_reg (feature, "r0", 0, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r1", 1, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r2", 2, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r3", 3, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r4", 4, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r5", 5, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r6", 6, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r7", 7, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r8", 8, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r9", 9, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r10", 10, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r11", 11, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r12", 12, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r13", 13, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r14", 14, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r15", 15, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r16", 16, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r17", 17, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r18", 18, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r19", 19, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r20", 20, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r21", 21, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r22", 22, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r23", 23, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r24", 24, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r25", 25, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r26", 26, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r27", 27, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r28", 28, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r29", 29, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r30", 30, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "r31", 31, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "pc", 64, 1, NULL, 64, "code_ptr");
|
||
+ tdesc_create_reg (feature, "msr", 65, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "cr", 66, 1, NULL, 32, "uint32");
|
||
+ tdesc_create_reg (feature, "lr", 67, 1, NULL, 64, "code_ptr");
|
||
+ tdesc_create_reg (feature, "ctr", 68, 1, NULL, 64, "uint64");
|
||
+ tdesc_create_reg (feature, "xer", 69, 1, NULL, 32, "uint32");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.fpu");
|
||
+ tdesc_create_reg (feature, "f0", 32, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f1", 33, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f2", 34, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f3", 35, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f4", 36, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f5", 37, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f6", 38, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f7", 39, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f8", 40, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f9", 41, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f10", 42, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f11", 43, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f12", 44, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f13", 45, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f14", 46, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f15", 47, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f16", 48, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f17", 49, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f18", 50, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f19", 51, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f20", 52, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f21", 53, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f22", 54, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f23", 55, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f24", 56, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f25", 57, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f26", 58, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f27", 59, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f28", 60, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f29", 61, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f30", 62, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "f31", 63, 1, NULL, 64, "ieee_double");
|
||
+ tdesc_create_reg (feature, "fpscr", 70, 1, "float", 32, "int");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux");
|
||
+ tdesc_create_reg (feature, "orig_r3", 71, 1, NULL, 64, "int");
|
||
+ tdesc_create_reg (feature, "trap", 72, 1, NULL, 64, "int");
|
||
+
|
||
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.altivec");
|
||
+ field_type = tdesc_named_type (feature, "ieee_single");
|
||
+ type = init_vector_type (field_type, 4);
|
||
+ TYPE_NAME (type) = xstrdup ("v4f");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int32");
|
||
+ type = init_vector_type (field_type, 4);
|
||
+ TYPE_NAME (type) = xstrdup ("v4i32");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int16");
|
||
+ type = init_vector_type (field_type, 8);
|
||
+ TYPE_NAME (type) = xstrdup ("v8i16");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ field_type = tdesc_named_type (feature, "int8");
|
||
+ type = init_vector_type (field_type, 16);
|
||
+ TYPE_NAME (type) = xstrdup ("v16i8");
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ type = init_composite_type (NULL, TYPE_CODE_UNION);
|
||
+ TYPE_NAME (type) = xstrdup ("vec128");
|
||
+ field_type = tdesc_named_type (feature, "uint128");
|
||
+ append_composite_type_field (type, xstrdup ("uint128"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v4f");
|
||
+ append_composite_type_field (type, xstrdup ("v4_float"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v4i32");
|
||
+ append_composite_type_field (type, xstrdup ("v4_int32"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v8i16");
|
||
+ append_composite_type_field (type, xstrdup ("v8_int16"), field_type);
|
||
+ field_type = tdesc_named_type (feature, "v16i8");
|
||
+ append_composite_type_field (type, xstrdup ("v16_int8"), field_type);
|
||
+ TYPE_VECTOR (type) = 1;
|
||
+ tdesc_record_type (feature, type);
|
||
+
|
||
+ tdesc_create_reg (feature, "vr0", 73, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr1", 74, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr2", 75, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr3", 76, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr4", 77, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr5", 78, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr6", 79, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr7", 80, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr8", 81, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr9", 82, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr10", 83, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr11", 84, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr12", 85, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr13", 86, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr14", 87, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr15", 88, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr16", 89, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr17", 90, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr18", 91, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr19", 92, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr20", 93, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr21", 94, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr22", 95, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr23", 96, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr24", 97, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr25", 98, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr26", 99, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr27", 100, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr28", 101, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr29", 102, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr30", 103, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vr31", 104, 1, NULL, 128, "vec128");
|
||
+ tdesc_create_reg (feature, "vscr", 105, 1, "vector", 32, "int");
|
||
+ tdesc_create_reg (feature, "vrsave", 106, 1, "vector", 32, "int");
|
||
+
|
||
+ tdesc_powerpc_cell64l = result;
|
||
+}
|
||
--- gdb/features/rs6000/powerpc-cell64l.xml
|
||
+++ gdb/features/rs6000/powerpc-cell64l.xml
|
||
@@ -0,0 +1,19 @@
|
||
+<?xml version="1.0"?>
|
||
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
|
||
+
|
||
+ Copying and distribution of this file, with or without modification,
|
||
+ are permitted in any medium without royalty provided the copyright
|
||
+ notice and this notice are preserved. -->
|
||
+
|
||
+<!-- Cell/B.E. architecture. Identical to the PowerPC 64-bit Linux UISA,
|
||
+ but adds support for the SPU as compatible architecture. -->
|
||
+
|
||
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||
+<target>
|
||
+ <architecture>powerpc:common64</architecture>
|
||
+ <compatible>spu</compatible>
|
||
+ <xi:include href="power64-core.xml"/>
|
||
+ <xi:include href="power-fpu.xml"/>
|
||
+ <xi:include href="power64-linux.xml"/>
|
||
+ <xi:include href="power-altivec.xml"/>
|
||
+</target>
|
||
--- gdb/findvar.c
|
||
+++ gdb/findvar.c
|
||
@@ -309,13 +309,15 @@ value_of_register_lazy (struct frame_inf
|
||
/* Given a pointer of type TYPE in target form in BUF, return the
|
||
address it represents. */
|
||
CORE_ADDR
|
||
-unsigned_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+unsigned_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
{
|
||
return extract_unsigned_integer (buf, TYPE_LENGTH (type));
|
||
}
|
||
|
||
CORE_ADDR
|
||
-signed_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+signed_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
{
|
||
return extract_signed_integer (buf, TYPE_LENGTH (type));
|
||
}
|
||
@@ -323,14 +325,15 @@ signed_pointer_to_address (struct type *
|
||
/* Given an address, store it as a pointer of type TYPE in target
|
||
format in BUF. */
|
||
void
|
||
-unsigned_address_to_pointer (struct type *type, gdb_byte *buf,
|
||
- CORE_ADDR addr)
|
||
+unsigned_address_to_pointer (struct gdbarch *gdbarch, struct type *type,
|
||
+ gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
store_unsigned_integer (buf, TYPE_LENGTH (type), addr);
|
||
}
|
||
|
||
void
|
||
-address_to_signed_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+address_to_signed_pointer (struct gdbarch *gdbarch, struct type *type,
|
||
+ gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
store_signed_integer (buf, TYPE_LENGTH (type), addr);
|
||
}
|
||
--- gdb/frame-unwind.c
|
||
+++ gdb/frame-unwind.c
|
||
@@ -126,7 +126,7 @@ default_frame_sniffer (const struct fram
|
||
struct value *
|
||
frame_unwind_got_optimized (struct frame_info *frame, int regnum)
|
||
{
|
||
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch *gdbarch = frame_arch_unwind (frame);
|
||
struct value *reg_val;
|
||
|
||
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
|
||
@@ -149,7 +149,7 @@ frame_unwind_got_register (struct frame_
|
||
struct value *
|
||
frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
|
||
{
|
||
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch *gdbarch = frame_arch_unwind (frame);
|
||
|
||
return value_at_lazy (register_type (gdbarch, regnum), addr);
|
||
}
|
||
@@ -161,7 +161,7 @@ struct value *
|
||
frame_unwind_got_constant (struct frame_info *frame, int regnum,
|
||
ULONGEST val)
|
||
{
|
||
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch *gdbarch = frame_arch_unwind (frame);
|
||
struct value *reg_val;
|
||
|
||
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
|
||
@@ -173,7 +173,7 @@ frame_unwind_got_constant (struct frame_
|
||
struct value *
|
||
frame_unwind_got_bytes (struct frame_info *frame, int regnum, gdb_byte *buf)
|
||
{
|
||
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch *gdbarch = frame_arch_unwind (frame);
|
||
struct value *reg_val;
|
||
|
||
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
|
||
@@ -189,7 +189,7 @@ struct value *
|
||
frame_unwind_got_address (struct frame_info *frame, int regnum,
|
||
CORE_ADDR addr)
|
||
{
|
||
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch *gdbarch = frame_arch_unwind (frame);
|
||
struct value *reg_val;
|
||
|
||
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
|
||
--- gdb/frame-unwind.h
|
||
+++ gdb/frame-unwind.h
|
||
@@ -121,6 +121,13 @@ typedef struct value * (frame_prev_regis
|
||
typedef void (frame_dealloc_cache_ftype) (struct frame_info *self,
|
||
void *this_cache);
|
||
|
||
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
||
+ use THIS frame, and implicitly the NEXT frame's register unwind
|
||
+ method, return PREV frame's architecture. */
|
||
+
|
||
+typedef struct gdbarch *(frame_prev_arch_ftype) (struct frame_info *this_frame,
|
||
+ void **this_prologue_cache);
|
||
+
|
||
struct frame_unwind
|
||
{
|
||
/* The frame's type. Should this instead be a collection of
|
||
@@ -133,6 +140,7 @@ struct frame_unwind
|
||
const struct frame_data *unwind_data;
|
||
frame_sniffer_ftype *sniffer;
|
||
frame_dealloc_cache_ftype *dealloc_cache;
|
||
+ frame_prev_arch_ftype *prev_arch;
|
||
};
|
||
|
||
/* Register a frame unwinder, _prepending_ it to the front of the
|
||
--- gdb/frame.c
|
||
+++ gdb/frame.c
|
||
@@ -41,6 +41,7 @@
|
||
#include "objfiles.h"
|
||
#include "exceptions.h"
|
||
#include "gdbthread.h"
|
||
+#include "arch-utils.h"
|
||
|
||
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
|
||
|
||
@@ -75,6 +76,13 @@ struct frame_info
|
||
void *prologue_cache;
|
||
const struct frame_unwind *unwind;
|
||
|
||
+ /* Cached copy of the previous frame's architecture. */
|
||
+ struct
|
||
+ {
|
||
+ int p;
|
||
+ struct gdbarch *arch;
|
||
+ } prev_arch;
|
||
+
|
||
/* Cached copy of the previous frame's resume address. */
|
||
struct {
|
||
int p;
|
||
@@ -190,6 +198,9 @@ fprint_frame_type (struct ui_file *file,
|
||
case SIGTRAMP_FRAME:
|
||
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
|
||
return;
|
||
+ case ARCH_FRAME:
|
||
+ fprintf_unfiltered (file, "ARCH_FRAME");
|
||
+ return;
|
||
default:
|
||
fprintf_unfiltered (file, "<unknown type>");
|
||
return;
|
||
@@ -251,6 +262,9 @@ get_frame_id (struct frame_info *fi)
|
||
}
|
||
if (!fi->this_id.p)
|
||
{
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (fi);
|
||
+
|
||
if (frame_debug)
|
||
fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
|
||
fi->level);
|
||
@@ -266,6 +280,8 @@ get_frame_id (struct frame_info *fi)
|
||
fprint_frame_id (gdb_stdlog, fi->this_id.value);
|
||
fprintf_unfiltered (gdb_stdlog, " }\n");
|
||
}
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
return fi->this_id.value;
|
||
}
|
||
@@ -459,7 +475,7 @@ frame_pc_unwind (struct frame_info *this
|
||
if (!this_frame->prev_pc.p)
|
||
{
|
||
CORE_ADDR pc;
|
||
- if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
|
||
+ if (gdbarch_unwind_pc_p (frame_arch_unwind (this_frame)))
|
||
{
|
||
/* The right way. The `pure' way. The one true way. This
|
||
method depends solely on the register-unwind code to
|
||
@@ -477,7 +493,7 @@ frame_pc_unwind (struct frame_info *this
|
||
frame. This is all in stark contrast to the old
|
||
FRAME_SAVED_PC which would try to directly handle all the
|
||
different ways that a PC could be unwound. */
|
||
- pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame);
|
||
+ pc = gdbarch_unwind_pc (frame_arch_unwind (this_frame), this_frame);
|
||
}
|
||
else
|
||
internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
|
||
@@ -650,19 +666,24 @@ get_frame_register (struct frame_info *f
|
||
struct value *
|
||
frame_unwind_register_value (struct frame_info *frame, int regnum)
|
||
{
|
||
+ struct gdbarch *gdbarch;
|
||
struct value *value;
|
||
+ struct cleanup *old_chain;
|
||
|
||
gdb_assert (frame != NULL);
|
||
+ gdbarch = frame_arch_unwind (frame);
|
||
|
||
if (frame_debug)
|
||
{
|
||
fprintf_unfiltered (gdb_stdlog, "\
|
||
{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
|
||
frame->level, regnum,
|
||
- user_reg_map_regnum_to_name
|
||
- (get_frame_arch (frame), regnum));
|
||
+ user_reg_map_regnum_to_name (gdbarch, regnum));
|
||
}
|
||
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = gdbarch;
|
||
+
|
||
/* Find the unwinder. */
|
||
if (frame->unwind == NULL)
|
||
frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
|
||
@@ -695,7 +716,7 @@ frame_unwind_register_value (struct fram
|
||
|
||
fprintf_unfiltered (gdb_stdlog, " bytes=");
|
||
fprintf_unfiltered (gdb_stdlog, "[");
|
||
- for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
|
||
+ for (i = 0; i < register_size (gdbarch, regnum); i++)
|
||
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
|
||
fprintf_unfiltered (gdb_stdlog, "]");
|
||
}
|
||
@@ -704,6 +725,7 @@ frame_unwind_register_value (struct fram
|
||
fprintf_unfiltered (gdb_stdlog, " }\n");
|
||
}
|
||
|
||
+ do_cleanups (old_chain);
|
||
return value;
|
||
}
|
||
|
||
@@ -718,7 +740,7 @@ frame_unwind_register_signed (struct fra
|
||
{
|
||
gdb_byte buf[MAX_REGISTER_SIZE];
|
||
frame_unwind_register (frame, regnum, buf);
|
||
- return extract_signed_integer (buf, register_size (get_frame_arch (frame),
|
||
+ return extract_signed_integer (buf, register_size (frame_arch_unwind (frame),
|
||
regnum));
|
||
}
|
||
|
||
@@ -733,7 +755,7 @@ frame_unwind_register_unsigned (struct f
|
||
{
|
||
gdb_byte buf[MAX_REGISTER_SIZE];
|
||
frame_unwind_register (frame, regnum, buf);
|
||
- return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
|
||
+ return extract_unsigned_integer (buf, register_size (frame_arch_unwind (frame),
|
||
regnum));
|
||
}
|
||
|
||
@@ -1070,6 +1092,8 @@ select_frame (struct frame_info *fi)
|
||
source language of this frame, and switch to it if desired. */
|
||
if (fi)
|
||
{
|
||
+ current_gdbarch = get_frame_arch (fi);
|
||
+
|
||
/* We retrieve the frame's symtab by using the frame PC. However
|
||
we cannot use the frame PC as-is, because it usually points to
|
||
the instruction following the "call", which is sometimes the
|
||
@@ -1694,9 +1718,17 @@ enum frame_type
|
||
get_frame_type (struct frame_info *frame)
|
||
{
|
||
if (frame->unwind == NULL)
|
||
- /* Initialize the frame's unwinder because that's what
|
||
- provides the frame's type. */
|
||
- frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
|
||
+ {
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (frame);
|
||
+
|
||
+ /* Initialize the frame's unwinder because that's what
|
||
+ provides the frame's type. */
|
||
+ frame->unwind = frame_unwind_find_by_frame (frame,
|
||
+ &frame->prologue_cache);
|
||
+ do_cleanups (old_chain);
|
||
+ }
|
||
+
|
||
return frame->unwind->type;
|
||
}
|
||
|
||
@@ -1731,17 +1763,48 @@ safe_frame_unwind_memory (struct frame_i
|
||
return !target_read_memory (addr, buf, len);
|
||
}
|
||
|
||
-/* Architecture method. */
|
||
+/* Architecture methods. */
|
||
|
||
struct gdbarch *
|
||
get_frame_arch (struct frame_info *this_frame)
|
||
{
|
||
- /* In the future, this function will return a per-frame
|
||
- architecture instead of current_gdbarch. Calling the
|
||
- routine with a NULL value of this_frame is a bug! */
|
||
- gdb_assert (this_frame);
|
||
+ return frame_arch_unwind (this_frame->next);
|
||
+}
|
||
+
|
||
+struct gdbarch *
|
||
+frame_arch_unwind (struct frame_info *next_frame)
|
||
+{
|
||
+ if (!next_frame->prev_arch.p)
|
||
+ {
|
||
+ struct gdbarch *arch;
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+
|
||
+ if (next_frame->level >= 0)
|
||
+ current_gdbarch = get_frame_arch (next_frame);
|
||
+
|
||
+ if (next_frame->unwind == NULL)
|
||
+ next_frame->unwind
|
||
+ = frame_unwind_find_by_frame (next_frame,
|
||
+ &next_frame->prologue_cache);
|
||
+
|
||
+ if (next_frame->unwind->prev_arch != NULL)
|
||
+ arch = next_frame->unwind->prev_arch (next_frame,
|
||
+ &next_frame->prologue_cache);
|
||
+ else
|
||
+ arch = get_frame_arch (next_frame);
|
||
+
|
||
+ next_frame->prev_arch.arch = arch;
|
||
+ next_frame->prev_arch.p = 1;
|
||
+ if (frame_debug)
|
||
+ fprintf_unfiltered (gdb_stdlog,
|
||
+ "{ frame_arch_unwind (next_frame=%d) -> %s }\n",
|
||
+ next_frame->level,
|
||
+ gdbarch_bfd_arch_info (arch)->printable_name);
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
+ }
|
||
|
||
- return current_gdbarch;
|
||
+ return next_frame->prev_arch.arch;
|
||
}
|
||
|
||
/* Stack pointer methods. */
|
||
--- gdb/frame.h
|
||
+++ gdb/frame.h
|
||
@@ -180,6 +180,8 @@ enum frame_type
|
||
/* In a signal handler, various OSs handle this in various ways.
|
||
The main thing is that the frame may be far from normal. */
|
||
SIGTRAMP_FRAME,
|
||
+ /* Fake frame representing a cross-architecture call. */
|
||
+ ARCH_FRAME,
|
||
/* Sentinel or registers frame. This frame obtains register values
|
||
direct from the inferior's registers. */
|
||
SENTINEL_FRAME
|
||
@@ -523,6 +525,7 @@ extern int safe_frame_unwind_memory (str
|
||
/* Return this frame's architecture. */
|
||
|
||
extern struct gdbarch *get_frame_arch (struct frame_info *this_frame);
|
||
+extern struct gdbarch *frame_arch_unwind (struct frame_info *next_frame);
|
||
|
||
|
||
/* Values for the source flag to be used in print_frame_info_base(). */
|
||
--- gdb/gcore.c
|
||
+++ gdb/gcore.c
|
||
@@ -35,7 +35,7 @@
|
||
generate-core-file for programs with large resident data. */
|
||
#define MAX_COPY_BYTES (1024 * 1024)
|
||
|
||
-static char *default_gcore_target (void);
|
||
+static const char *default_gcore_target (void);
|
||
static enum bfd_architecture default_gcore_arch (void);
|
||
static unsigned long default_gcore_mach (void);
|
||
static int gcore_memory_sections (bfd *);
|
||
@@ -125,7 +125,7 @@ default_gcore_mach (void)
|
||
return 0;
|
||
#else
|
||
|
||
- const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (current_gdbarch);
|
||
+ const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch);
|
||
|
||
if (bfdarch != NULL)
|
||
return bfdarch->mach;
|
||
@@ -139,8 +139,7 @@ default_gcore_mach (void)
|
||
static enum bfd_architecture
|
||
default_gcore_arch (void)
|
||
{
|
||
- const struct bfd_arch_info * bfdarch = gdbarch_bfd_arch_info
|
||
- (current_gdbarch);
|
||
+ const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch);
|
||
|
||
if (bfdarch != NULL)
|
||
return bfdarch->arch;
|
||
@@ -150,10 +149,15 @@ default_gcore_arch (void)
|
||
return bfd_get_arch (exec_bfd);
|
||
}
|
||
|
||
-static char *
|
||
+static const char *
|
||
default_gcore_target (void)
|
||
{
|
||
- /* FIXME: This may only work for ELF targets. */
|
||
+ /* The gdbarch may define a target to use for core files. */
|
||
+ if (gdbarch_gcore_bfd_target_p (target_gdbarch))
|
||
+ return gdbarch_gcore_bfd_target (target_gdbarch);
|
||
+
|
||
+ /* Otherwise, try to fall back to the exec_bfd target. This will probably
|
||
+ not work for non-ELF targets. */
|
||
if (exec_bfd == NULL)
|
||
return NULL;
|
||
else
|
||
--- gdb/gdbarch.c
|
||
+++ gdb/gdbarch.c
|
||
@@ -226,6 +226,7 @@ struct gdbarch
|
||
int core_reg_section_encodes_pid;
|
||
struct core_regset_section * core_regset_sections;
|
||
gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
|
||
+ const char * gcore_bfd_target;
|
||
int vtable_function_descriptors;
|
||
int vbit_in_delta;
|
||
gdbarch_skip_permanent_breakpoint_ftype *skip_permanent_breakpoint;
|
||
@@ -314,8 +315,8 @@ struct gdbarch startup_gdbarch =
|
||
0, /* register_to_value */
|
||
0, /* value_to_register */
|
||
0, /* value_from_register */
|
||
- 0, /* pointer_to_address */
|
||
- 0, /* address_to_pointer */
|
||
+ unsigned_pointer_to_address, /* pointer_to_address */
|
||
+ unsigned_address_to_pointer, /* address_to_pointer */
|
||
0, /* integer_to_address */
|
||
0, /* return_value */
|
||
0, /* skip_prologue */
|
||
@@ -360,6 +361,7 @@ struct gdbarch startup_gdbarch =
|
||
0, /* core_reg_section_encodes_pid */
|
||
0, /* core_regset_sections */
|
||
0, /* core_xfer_shared_libraries */
|
||
+ 0, /* gcore_bfd_target */
|
||
0, /* vtable_function_descriptors */
|
||
0, /* vbit_in_delta */
|
||
0, /* skip_permanent_breakpoint */
|
||
@@ -613,6 +615,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
|
||
/* Skip verify of regset_from_core_section, has predicate */
|
||
/* Skip verify of core_reg_section_encodes_pid, invalid_p == 0 */
|
||
/* Skip verify of core_xfer_shared_libraries, has predicate */
|
||
+ /* Skip verify of gcore_bfd_target, has predicate */
|
||
/* Skip verify of vtable_function_descriptors, invalid_p == 0 */
|
||
/* Skip verify of vbit_in_delta, invalid_p == 0 */
|
||
/* Skip verify of skip_permanent_breakpoint, has predicate */
|
||
@@ -838,6 +841,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
|
||
"gdbarch_dump: frame_red_zone_size = %s\n",
|
||
plongest (gdbarch->frame_red_zone_size));
|
||
fprintf_unfiltered (file,
|
||
+ "gdbarch_dump: gdbarch_gcore_bfd_target_p() = %d\n",
|
||
+ gdbarch_gcore_bfd_target_p (gdbarch));
|
||
+ fprintf_unfiltered (file,
|
||
+ "gdbarch_dump: gcore_bfd_target = %s\n",
|
||
+ gdbarch->gcore_bfd_target);
|
||
+ fprintf_unfiltered (file,
|
||
"gdbarch_dump: gdbarch_get_longjmp_target_p() = %d\n",
|
||
gdbarch_get_longjmp_target_p (gdbarch));
|
||
fprintf_unfiltered (file,
|
||
@@ -2070,7 +2079,7 @@ gdbarch_pointer_to_address (struct gdbar
|
||
gdb_assert (gdbarch->pointer_to_address != NULL);
|
||
if (gdbarch_debug >= 2)
|
||
fprintf_unfiltered (gdb_stdlog, "gdbarch_pointer_to_address called\n");
|
||
- return gdbarch->pointer_to_address (type, buf);
|
||
+ return gdbarch->pointer_to_address (gdbarch, type, buf);
|
||
}
|
||
|
||
void
|
||
@@ -2087,7 +2096,7 @@ gdbarch_address_to_pointer (struct gdbar
|
||
gdb_assert (gdbarch->address_to_pointer != NULL);
|
||
if (gdbarch_debug >= 2)
|
||
fprintf_unfiltered (gdb_stdlog, "gdbarch_address_to_pointer called\n");
|
||
- gdbarch->address_to_pointer (type, buf, addr);
|
||
+ gdbarch->address_to_pointer (gdbarch, type, buf, addr);
|
||
}
|
||
|
||
void
|
||
@@ -2963,6 +2972,31 @@ set_gdbarch_core_xfer_shared_libraries (
|
||
}
|
||
|
||
int
|
||
+gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch)
|
||
+{
|
||
+ gdb_assert (gdbarch != NULL);
|
||
+ return gdbarch->gcore_bfd_target != 0;
|
||
+}
|
||
+
|
||
+const char *
|
||
+gdbarch_gcore_bfd_target (struct gdbarch *gdbarch)
|
||
+{
|
||
+ gdb_assert (gdbarch != NULL);
|
||
+ /* Check variable changed from pre-default. */
|
||
+ gdb_assert (gdbarch->gcore_bfd_target != 0);
|
||
+ if (gdbarch_debug >= 2)
|
||
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_gcore_bfd_target called\n");
|
||
+ return gdbarch->gcore_bfd_target;
|
||
+}
|
||
+
|
||
+void
|
||
+set_gdbarch_gcore_bfd_target (struct gdbarch *gdbarch,
|
||
+ const char * gcore_bfd_target)
|
||
+{
|
||
+ gdbarch->gcore_bfd_target = gcore_bfd_target;
|
||
+}
|
||
+
|
||
+int
|
||
gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch)
|
||
{
|
||
gdb_assert (gdbarch != NULL);
|
||
@@ -3423,10 +3457,15 @@ gdbarch_data (struct gdbarch *gdbarch, s
|
||
(as all fields are valid), but be careful to also detect
|
||
recursive references. */
|
||
{
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = gdbarch;
|
||
+
|
||
gdb_assert (data->init_p);
|
||
data->init_p = 0;
|
||
gdbarch->data[data->index] = data->post_init (gdbarch);
|
||
data->init_p = 1;
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
else
|
||
/* The architecture initialization hasn't completed - punt -
|
||
--- gdb/gdbarch.h
|
||
+++ gdb/gdbarch.h
|
||
@@ -348,11 +348,11 @@ typedef struct value * (gdbarch_value_fr
|
||
extern struct value * gdbarch_value_from_register (struct gdbarch *gdbarch, struct type *type, int regnum, struct frame_info *frame);
|
||
extern void set_gdbarch_value_from_register (struct gdbarch *gdbarch, gdbarch_value_from_register_ftype *value_from_register);
|
||
|
||
-typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct type *type, const gdb_byte *buf);
|
||
+typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
|
||
extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
|
||
extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
|
||
|
||
-typedef void (gdbarch_address_to_pointer_ftype) (struct type *type, gdb_byte *buf, CORE_ADDR addr);
|
||
+typedef void (gdbarch_address_to_pointer_ftype) (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr);
|
||
extern void gdbarch_address_to_pointer (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr);
|
||
extern void set_gdbarch_address_to_pointer (struct gdbarch *gdbarch, gdbarch_address_to_pointer_ftype *address_to_pointer);
|
||
|
||
@@ -661,6 +661,13 @@ typedef LONGEST (gdbarch_core_xfer_share
|
||
extern LONGEST gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len);
|
||
extern void set_gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries);
|
||
|
||
+/* BFD target to use when generating a core file. */
|
||
+
|
||
+extern int gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch);
|
||
+
|
||
+extern const char * gdbarch_gcore_bfd_target (struct gdbarch *gdbarch);
|
||
+extern void set_gdbarch_gcore_bfd_target (struct gdbarch *gdbarch, const char * gcore_bfd_target);
|
||
+
|
||
/* If the elements of C++ vtables are in-place function descriptors rather
|
||
than normal function pointers (which may point to code or a descriptor),
|
||
set this to one. */
|
||
--- gdb/gdbarch.sh
|
||
+++ gdb/gdbarch.sh
|
||
@@ -466,8 +466,8 @@ f:void:value_to_register:struct frame_in
|
||
# (but not the value contents) filled in.
|
||
f:struct value *:value_from_register:struct type *type, int regnum, struct frame_info *frame:type, regnum, frame::default_value_from_register::0
|
||
#
|
||
-f:CORE_ADDR:pointer_to_address:struct type *type, const gdb_byte *buf:type, buf::unsigned_pointer_to_address::0
|
||
-f:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
|
||
+m:CORE_ADDR:pointer_to_address:struct type *type, const gdb_byte *buf:type, buf::unsigned_pointer_to_address::0
|
||
+m:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
|
||
M:CORE_ADDR:integer_to_address:struct type *type, const gdb_byte *buf:type, buf
|
||
|
||
# Return the return-value convention that will be used by FUNCTYPE
|
||
@@ -614,6 +614,9 @@ v:struct core_regset_section *:core_regs
|
||
# core file into buffer READBUF with length LEN.
|
||
M:LONGEST:core_xfer_shared_libraries:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len
|
||
|
||
+# BFD target to use when generating a core file.
|
||
+V:const char *:gcore_bfd_target:::0:0:::gdbarch->gcore_bfd_target
|
||
+
|
||
# If the elements of C++ vtables are in-place function descriptors rather
|
||
# than normal function pointers (which may point to code or a descriptor),
|
||
# set this to one.
|
||
@@ -1743,10 +1746,15 @@ gdbarch_data (struct gdbarch *gdbarch, s
|
||
(as all fields are valid), but be careful to also detect
|
||
recursive references. */
|
||
{
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = gdbarch;
|
||
+
|
||
gdb_assert (data->init_p);
|
||
data->init_p = 0;
|
||
gdbarch->data[data->index] = data->post_init (gdbarch);
|
||
data->init_p = 1;
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
else
|
||
/* The architecture initialization hasn't completed - punt -
|
||
--- gdb/gdbserver/Makefile.in
|
||
+++ gdb/gdbserver/Makefile.in
|
||
@@ -207,8 +207,8 @@ clean:
|
||
rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c
|
||
rm -f arm-with-iwmmxt.c mips-linux.c mips64-linux.c
|
||
rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c
|
||
- rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c
|
||
- rm -f powerpc-vsx64l.c
|
||
+ rm -f powerpc-altivec32l.c powerpc-cell32l.c powerpc-vsx32l.c
|
||
+ rm -f powerpc-altivec64l.c powerpc-cell64l.c powerpc-vsx64l.c
|
||
rm -f powerpc-isa205-32l.c powerpc-isa205-64l.c
|
||
rm -f powerpc-isa205-altivec32l.c powerpc-isa205-vsx32l.c powerpc-isa205-altivec64l.c
|
||
rm -f powerpc-isa205-vsx64l.c
|
||
@@ -356,6 +356,9 @@ powerpc-32l.c : $(srcdir)/../regformats/
|
||
powerpc-altivec32l.o : powerpc-altivec32l.c $(regdef_h)
|
||
powerpc-altivec32l.c : $(srcdir)/../regformats/rs6000/powerpc-altivec32l.dat $(regdat_sh)
|
||
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-altivec32l.dat powerpc-altivec32l.c
|
||
+powerpc-cell32l.o : powerpc-cell32l.c $(regdef_h)
|
||
+powerpc-cell32l.c : $(srcdir)/../regformats/rs6000/powerpc-cell32l.dat $(regdat_sh)
|
||
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-cell32l.dat powerpc-cell32l.c
|
||
powerpc-vsx32l.o : powerpc-vsx32l.c $(regdef_h)
|
||
powerpc-vsx32l.c : $(srcdir)/../regformats/rs6000/powerpc-vsx32l.dat $(regdat_sh)
|
||
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-vsx32l.dat powerpc-vsx32l.c
|
||
@@ -377,6 +380,9 @@ powerpc-64l.c : $(srcdir)/../regformats/
|
||
powerpc-altivec64l.o : powerpc-altivec64l.c $(regdef_h)
|
||
powerpc-altivec64l.c : $(srcdir)/../regformats/rs6000/powerpc-altivec64l.dat $(regdat_sh)
|
||
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-altivec64l.dat powerpc-altivec64l.c
|
||
+powerpc-cell64l.o : powerpc-cell64l.c $(regdef_h)
|
||
+powerpc-cell64l.c : $(srcdir)/../regformats/rs6000/powerpc-cell64l.dat $(regdat_sh)
|
||
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-cell64l.dat powerpc-cell64l.c
|
||
powerpc-vsx64l.o : powerpc-vsx64l.c $(regdef_h)
|
||
powerpc-vsx64l.c : $(srcdir)/../regformats/rs6000/powerpc-vsx64l.dat $(regdat_sh)
|
||
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-vsx64l.dat powerpc-vsx64l.c
|
||
--- gdb/gdbserver/configure.srv
|
||
+++ gdb/gdbserver/configure.srv
|
||
@@ -102,6 +102,7 @@ case "${target}" in
|
||
;;
|
||
powerpc*-*-linux*) srv_regobj="powerpc-32l.o"
|
||
srv_regobj="${srv_regobj} powerpc-altivec32l.o"
|
||
+ srv_regobj="${srv_regobj} powerpc-cell32l.o"
|
||
srv_regobj="${srv_regobj} powerpc-vsx32l.o"
|
||
srv_regobj="${srv_regobj} powerpc-isa205-32l.o"
|
||
srv_regobj="${srv_regobj} powerpc-isa205-altivec32l.o"
|
||
@@ -109,6 +110,7 @@ case "${target}" in
|
||
srv_regobj="${srv_regobj} powerpc-e500l.o"
|
||
srv_regobj="${srv_regobj} powerpc-64l.o"
|
||
srv_regobj="${srv_regobj} powerpc-altivec64l.o"
|
||
+ srv_regobj="${srv_regobj} powerpc-cell64l.o"
|
||
srv_regobj="${srv_regobj} powerpc-vsx64l.o"
|
||
srv_regobj="${srv_regobj} powerpc-isa205-64l.o"
|
||
srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o"
|
||
@@ -116,6 +118,7 @@ case "${target}" in
|
||
srv_tgtobj="linux-low.o linux-ppc-low.o"
|
||
srv_xmlfiles="rs6000/powerpc-32l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml"
|
||
+ srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-cell32l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx32l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-32l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec32l.xml"
|
||
@@ -130,6 +133,7 @@ case "${target}" in
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec64l.xml"
|
||
+ srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-cell64l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx64l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-64l.xml"
|
||
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec64l.xml"
|
||
--- gdb/gdbserver/linux-low.c
|
||
+++ gdb/gdbserver/linux-low.c
|
||
@@ -36,8 +36,14 @@
|
||
#include <ctype.h>
|
||
#include <pwd.h>
|
||
#include <sys/types.h>
|
||
+#include <sys/stat.h>
|
||
+#include <sys/vfs.h>
|
||
#include <dirent.h>
|
||
|
||
+#ifndef SPUFS_MAGIC
|
||
+#define SPUFS_MAGIC 0x23c9b64e
|
||
+#endif
|
||
+
|
||
#ifndef PTRACE_GETSIGINFO
|
||
# define PTRACE_GETSIGINFO 0x4202
|
||
# define PTRACE_SETSIGINFO 0x4203
|
||
@@ -2218,6 +2224,102 @@ linux_xfer_siginfo (const char *annex, u
|
||
return len;
|
||
}
|
||
|
||
+
|
||
+/* Enumerate spufs IDs for process PID. */
|
||
+static int
|
||
+spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
|
||
+{
|
||
+ int pos = 0;
|
||
+ int written = 0;
|
||
+ char path[128];
|
||
+ DIR *dir;
|
||
+ struct dirent *entry;
|
||
+
|
||
+ sprintf (path, "/proc/%ld/fd", pid);
|
||
+ dir = opendir (path);
|
||
+ if (!dir)
|
||
+ return -1;
|
||
+
|
||
+ rewinddir (dir);
|
||
+ while ((entry = readdir (dir)) != NULL)
|
||
+ {
|
||
+ struct stat st;
|
||
+ struct statfs stfs;
|
||
+ int fd;
|
||
+
|
||
+ fd = atoi (entry->d_name);
|
||
+ if (!fd)
|
||
+ continue;
|
||
+
|
||
+ sprintf (path, "/proc/%ld/fd/%d", pid, fd);
|
||
+ if (stat (path, &st) != 0)
|
||
+ continue;
|
||
+ if (!S_ISDIR (st.st_mode))
|
||
+ continue;
|
||
+
|
||
+ if (statfs (path, &stfs) != 0)
|
||
+ continue;
|
||
+ if (stfs.f_type != SPUFS_MAGIC)
|
||
+ continue;
|
||
+
|
||
+ if (pos >= offset && pos + 4 <= offset + len)
|
||
+ {
|
||
+ *(unsigned int *)(buf + pos - offset) = fd;
|
||
+ written += 4;
|
||
+ }
|
||
+ pos += 4;
|
||
+ }
|
||
+
|
||
+ closedir (dir);
|
||
+ return written;
|
||
+}
|
||
+
|
||
+/* Implements the to_xfer_partial interface for the TARGET_OBJECT_SPU
|
||
+ object type, using the /proc file system */
|
||
+static int
|
||
+linux_spu_qxfer_partial (const char *annex, unsigned char *readbuf,
|
||
+ unsigned const char *writebuf,
|
||
+ CORE_ADDR offset, int len)
|
||
+{
|
||
+ char buf[128];
|
||
+ int fd = 0;
|
||
+ int ret = 0;
|
||
+
|
||
+ if (!writebuf && !readbuf)
|
||
+ return -1;
|
||
+
|
||
+ if (!*annex)
|
||
+ {
|
||
+ if (!readbuf)
|
||
+ return -1;
|
||
+ else
|
||
+ return spu_enumerate_spu_ids (inferior_pid, readbuf, offset, len);
|
||
+ }
|
||
+
|
||
+ sprintf (buf, "/proc/%ld/fd/%s", inferior_pid, annex);
|
||
+ if (debug_threads)
|
||
+ printf ("access [%s] |offset [%lld] | len [%d]\n", buf, offset, len);
|
||
+
|
||
+ fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
|
||
+ if (fd <= 0)
|
||
+ return -1;
|
||
+
|
||
+ if (offset != 0
|
||
+ && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
|
||
+ {
|
||
+ close (fd);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (writebuf)
|
||
+ ret = write (fd, writebuf, (size_t) len);
|
||
+ else
|
||
+ ret = read (fd, readbuf, (size_t) len);
|
||
+
|
||
+ close (fd);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
static struct target_ops linux_target_ops = {
|
||
linux_create_inferior,
|
||
linux_attach,
|
||
@@ -2248,7 +2350,7 @@ static struct target_ops linux_target_op
|
||
#else
|
||
NULL,
|
||
#endif
|
||
- NULL,
|
||
+ linux_spu_qxfer_partial,
|
||
hostio_last_error_from_errno,
|
||
linux_qxfer_osdata,
|
||
linux_xfer_siginfo,
|
||
--- gdb/gdbserver/linux-ppc-low.c
|
||
+++ gdb/gdbserver/linux-ppc-low.c
|
||
@@ -28,6 +28,7 @@
|
||
#define PPC_FEATURE_HAS_VSX 0x00000080
|
||
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
|
||
#define PPC_FEATURE_HAS_SPE 0x00800000
|
||
+#define PPC_FEATURE_CELL 0x00010000
|
||
#define PPC_FEATURE_ARCH_2_05 0x00001000
|
||
|
||
static unsigned long ppc_hwcap;
|
||
@@ -37,6 +38,8 @@ static unsigned long ppc_hwcap;
|
||
void init_registers_powerpc_32l (void);
|
||
/* Defined in auto-generated file powerpc-altivec32l.c. */
|
||
void init_registers_powerpc_altivec32l (void);
|
||
+/* Defined in auto-generated file powerpc-cell32l.c. */
|
||
+void init_registers_powerpc_cell32l (void);
|
||
/* Defined in auto-generated file powerpc-vsx32l.c. */
|
||
void init_registers_powerpc_vsx32l (void);
|
||
/* Defined in auto-generated file powerpc-isa205-32l.c. */
|
||
@@ -51,6 +54,8 @@ void init_registers_powerpc_e500l (void)
|
||
void init_registers_powerpc_64l (void);
|
||
/* Defined in auto-generated file powerpc-altivec64l.c. */
|
||
void init_registers_powerpc_altivec64l (void);
|
||
+/* Defined in auto-generated file powerpc-cell64l.c. */
|
||
+void init_registers_powerpc_cell64l (void);
|
||
/* Defined in auto-generated file powerpc-vsx64l.c. */
|
||
void init_registers_powerpc_vsx64l (void);
|
||
/* Defined in auto-generated file powerpc-isa205-64l.c. */
|
||
@@ -186,10 +191,72 @@ ppc_supply_ptrace_register (int regno, c
|
||
supply_register (regno, buf);
|
||
}
|
||
|
||
+
|
||
+#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 (int *fd, CORE_ADDR *addr)
|
||
+{
|
||
+ CORE_ADDR curr_pc;
|
||
+ int curr_insn;
|
||
+ int curr_r0;
|
||
+
|
||
+ if (register_size (0) == 4)
|
||
+ {
|
||
+ unsigned int pc, r0, r3, r4;
|
||
+ collect_register_by_name ("pc", &pc);
|
||
+ collect_register_by_name ("r0", &r0);
|
||
+ collect_register_by_name ("orig_r3", &r3);
|
||
+ collect_register_by_name ("r4", &r4);
|
||
+ curr_pc = (CORE_ADDR) pc;
|
||
+ curr_r0 = (int) r0;
|
||
+ *fd = (int) r3;
|
||
+ *addr = (CORE_ADDR) r4;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ unsigned long pc, r0, r3, r4;
|
||
+ collect_register_by_name ("pc", &pc);
|
||
+ collect_register_by_name ("r0", &r0);
|
||
+ collect_register_by_name ("orig_r3", &r3);
|
||
+ collect_register_by_name ("r4", &r4);
|
||
+ curr_pc = (CORE_ADDR) pc;
|
||
+ curr_r0 = (int) r0;
|
||
+ *fd = (int) r3;
|
||
+ *addr = (CORE_ADDR) r4;
|
||
+ }
|
||
+
|
||
+ /* Fetch instruction preceding current NIP. */
|
||
+ if ((*the_target->read_memory) (curr_pc - 4,
|
||
+ (unsigned char *) &curr_insn, 4) != 0)
|
||
+ return 0;
|
||
+ /* It should be a "sc" instruction. */
|
||
+ if (curr_insn != INSTR_SC)
|
||
+ return 0;
|
||
+ /* System call number should be NR_spu_run. */
|
||
+ if (curr_r0 != NR_spu_run)
|
||
+ return 0;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
static CORE_ADDR
|
||
ppc_get_pc (void)
|
||
{
|
||
- if (register_size (0) == 4)
|
||
+ CORE_ADDR addr;
|
||
+ int fd;
|
||
+
|
||
+ if (parse_spufs_run (&fd, &addr))
|
||
+ {
|
||
+ unsigned int pc;
|
||
+ (*the_target->read_memory) (addr, (unsigned char *) &pc, 4);
|
||
+ return ((CORE_ADDR)1 << 63) | ((CORE_ADDR)fd << 32) | (CORE_ADDR) (pc - 4);
|
||
+ }
|
||
+ else if (register_size (0) == 4)
|
||
{
|
||
unsigned int pc;
|
||
collect_register_by_name ("pc", &pc);
|
||
@@ -206,7 +273,15 @@ ppc_get_pc (void)
|
||
static void
|
||
ppc_set_pc (CORE_ADDR pc)
|
||
{
|
||
- if (register_size (0) == 4)
|
||
+ CORE_ADDR addr;
|
||
+ int fd;
|
||
+
|
||
+ if (parse_spufs_run (&fd, &addr))
|
||
+ {
|
||
+ unsigned int newpc = pc;
|
||
+ (*the_target->write_memory) (addr, (unsigned char *) &newpc, 4);
|
||
+ }
|
||
+ else if (register_size (0) == 4)
|
||
{
|
||
unsigned int newpc = pc;
|
||
supply_register_by_name ("pc", &newpc);
|
||
@@ -272,7 +347,9 @@ ppc_arch_setup (void)
|
||
if (msr < 0)
|
||
{
|
||
ppc_get_hwcap (&ppc_hwcap);
|
||
- if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
|
||
+ if (ppc_hwcap & PPC_FEATURE_CELL)
|
||
+ init_registers_powerpc_cell64l ();
|
||
+ else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
|
||
{
|
||
if (ppc_hwcap & PPC_FEATURE_ARCH_2_05)
|
||
init_registers_powerpc_isa205_vsx64l ();
|
||
@@ -295,7 +372,9 @@ ppc_arch_setup (void)
|
||
init_registers_powerpc_32l ();
|
||
|
||
ppc_get_hwcap (&ppc_hwcap);
|
||
- if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
|
||
+ if (ppc_hwcap & PPC_FEATURE_CELL)
|
||
+ init_registers_powerpc_cell32l ();
|
||
+ else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
|
||
{
|
||
if (ppc_hwcap & PPC_FEATURE_ARCH_2_05)
|
||
init_registers_powerpc_isa205_vsx32l ();
|
||
@@ -339,11 +418,24 @@ ppc_breakpoint_at (CORE_ADDR where)
|
||
{
|
||
unsigned int insn;
|
||
|
||
- (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
|
||
- if (insn == ppc_breakpoint)
|
||
- return 1;
|
||
- /* If necessary, recognize more trap instructions here. GDB only uses the
|
||
- one. */
|
||
+ if (where & ((CORE_ADDR)1 << 63))
|
||
+ {
|
||
+ char mem_annex[32];
|
||
+ sprintf (mem_annex, "%d/mem", (int)((where >> 32) & 0x7fffffff));
|
||
+ (*the_target->qxfer_spu) (mem_annex, (unsigned char *) &insn,
|
||
+ NULL, where & 0xffffffff, 4);
|
||
+ if (insn == 0x3fff)
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
|
||
+ if (insn == ppc_breakpoint)
|
||
+ return 1;
|
||
+ /* If necessary, recognize more trap instructions here. GDB only uses
|
||
+ the one. */
|
||
+ }
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
--- gdb/gdbserver/thread-db.c
|
||
+++ gdb/gdbserver/thread-db.c
|
||
@@ -386,6 +386,10 @@ thread_db_get_tls_address (struct thread
|
||
td_err_e err;
|
||
struct process_info *process;
|
||
|
||
+ /* If the thread layer is not (yet) initialized, fail. */
|
||
+ if (!all_symbols_looked_up)
|
||
+ return -1;
|
||
+
|
||
process = get_thread_process (thread);
|
||
if (!process->thread_known)
|
||
find_one_thread (process->lwpid);
|
||
--- gdb/i386-nat.c
|
||
+++ gdb/i386-nat.c
|
||
@@ -641,14 +641,14 @@ i386_insert_hw_breakpoint (struct bp_tar
|
||
}
|
||
|
||
/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address.
|
||
- Return 0 on success, -1 on failure. */
|
||
+ Return 0 on success, EBUSY on failure. */
|
||
|
||
int
|
||
i386_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
|
||
{
|
||
unsigned len_rw = i386_length_and_rw_bits (1, hw_execute);
|
||
CORE_ADDR addr = bp_tgt->placed_address;
|
||
- int retval = i386_remove_aligned_watchpoint (addr, len_rw);
|
||
+ int retval = i386_remove_aligned_watchpoint (addr, len_rw) ? EBUSY : 0;
|
||
|
||
if (maint_show_dr)
|
||
i386_show_dr ("remove_hwbp", addr, 1, hw_execute);
|
||
--- gdb/inferior.h
|
||
+++ gdb/inferior.h
|
||
@@ -156,13 +156,17 @@ extern CORE_ADDR read_pc (void);
|
||
|
||
extern void write_pc (CORE_ADDR);
|
||
|
||
-extern CORE_ADDR unsigned_pointer_to_address (struct type *type,
|
||
+extern CORE_ADDR unsigned_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type,
|
||
const gdb_byte *buf);
|
||
-extern void unsigned_address_to_pointer (struct type *type, gdb_byte *buf,
|
||
+extern void unsigned_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf,
|
||
CORE_ADDR addr);
|
||
-extern CORE_ADDR signed_pointer_to_address (struct type *type,
|
||
+extern CORE_ADDR signed_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type,
|
||
const gdb_byte *buf);
|
||
-extern void address_to_signed_pointer (struct type *type, gdb_byte *buf,
|
||
+extern void address_to_signed_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf,
|
||
CORE_ADDR addr);
|
||
|
||
extern void wait_for_inferior (int treat_exec_as_sigtrap);
|
||
--- gdb/iq2000-tdep.c
|
||
+++ gdb/iq2000-tdep.c
|
||
@@ -87,7 +87,8 @@ insn_addr_from_ptr (CORE_ADDR ptr) /* ta
|
||
Convert a target pointer to an address in host (CORE_ADDR) format. */
|
||
|
||
static CORE_ADDR
|
||
-iq2000_pointer_to_address (struct type * type, const gdb_byte * buf)
|
||
+iq2000_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type * type, const gdb_byte * buf)
|
||
{
|
||
enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
|
||
CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
|
||
@@ -104,7 +105,8 @@ iq2000_pointer_to_address (struct type *
|
||
Convert a host-format address (CORE_ADDR) into a target pointer. */
|
||
|
||
static void
|
||
-iq2000_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+iq2000_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
|
||
|
||
--- gdb/linux-nat.c
|
||
+++ gdb/linux-nat.c
|
||
@@ -53,6 +53,12 @@
|
||
#include <sys/types.h>
|
||
#include "gdb_dirent.h"
|
||
#include "xml-support.h"
|
||
+#include <sys/vfs.h> /* for struct statfs */
|
||
+#include <dirent.h> /* for DIR etc. */
|
||
+
|
||
+#ifndef SPUFS_MAGIC
|
||
+#define SPUFS_MAGIC 0x23c9b64e
|
||
+#endif
|
||
|
||
#ifdef HAVE_PERSONALITY
|
||
# include <sys/personality.h>
|
||
@@ -3529,8 +3535,8 @@ linux_nat_do_thread_registers (bfd *obfd
|
||
gdb_gregset_t gregs;
|
||
gdb_fpregset_t fpregs;
|
||
unsigned long lwp = ptid_get_lwp (ptid);
|
||
- struct regcache *regcache = get_thread_regcache (ptid);
|
||
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||
+ struct gdbarch *gdbarch = target_gdbarch;
|
||
+ struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
|
||
const struct regset *regset;
|
||
int core_regset_p;
|
||
struct cleanup *old_chain;
|
||
@@ -3640,6 +3646,119 @@ linux_nat_corefile_thread_callback (stru
|
||
return 0;
|
||
}
|
||
|
||
+/* Enumerate spufs IDs for process PID. */
|
||
+
|
||
+static void
|
||
+iterate_over_spus (int pid, void (*callback) (void *, int), void *data)
|
||
+{
|
||
+ char path[128];
|
||
+ DIR *dir;
|
||
+ struct dirent *entry;
|
||
+
|
||
+ xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
|
||
+ dir = opendir (path);
|
||
+ if (!dir)
|
||
+ return;
|
||
+
|
||
+ rewinddir (dir);
|
||
+ while ((entry = readdir (dir)) != NULL)
|
||
+ {
|
||
+ struct stat st;
|
||
+ struct statfs stfs;
|
||
+ int fd;
|
||
+
|
||
+ fd = atoi (entry->d_name);
|
||
+ if (!fd)
|
||
+ continue;
|
||
+
|
||
+ xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
|
||
+ if (stat (path, &st) != 0)
|
||
+ continue;
|
||
+ if (!S_ISDIR (st.st_mode))
|
||
+ continue;
|
||
+
|
||
+ if (statfs (path, &stfs) != 0)
|
||
+ continue;
|
||
+ if (stfs.f_type != SPUFS_MAGIC)
|
||
+ continue;
|
||
+
|
||
+ callback (data, fd);
|
||
+ }
|
||
+
|
||
+ closedir (dir);
|
||
+}
|
||
+
|
||
+/* Generate corefile notes for SPU contexts. */
|
||
+
|
||
+struct linux_spu_corefile_data
|
||
+{
|
||
+ bfd *obfd;
|
||
+ char *note_data;
|
||
+ int *note_size;
|
||
+};
|
||
+
|
||
+static void
|
||
+linux_spu_corefile_callback (void *data, int fd)
|
||
+{
|
||
+ struct linux_spu_corefile_data *args = data;
|
||
+ int i;
|
||
+
|
||
+ static const char *spu_files[] =
|
||
+ {
|
||
+ "object-id",
|
||
+ "mem",
|
||
+ "regs",
|
||
+ "fpcr",
|
||
+ "lslr",
|
||
+ "decr",
|
||
+ "decr_status",
|
||
+ "signal1",
|
||
+ "signal1_type",
|
||
+ "signal2",
|
||
+ "signal2_type",
|
||
+ "event_mask",
|
||
+ "event_status",
|
||
+ "mbox_info",
|
||
+ "ibox_info",
|
||
+ "wbox_info",
|
||
+ "dma_info",
|
||
+ "proxydma_info",
|
||
+ };
|
||
+
|
||
+ for (i = 0; i < sizeof (spu_files) / sizeof (spu_files[0]); i++)
|
||
+ {
|
||
+ char annex[32], note_name[32];
|
||
+ gdb_byte *spu_data;
|
||
+ LONGEST spu_len;
|
||
+
|
||
+ xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[i]);
|
||
+ spu_len = target_read_alloc (¤t_target, TARGET_OBJECT_SPU,
|
||
+ annex, &spu_data);
|
||
+ if (spu_len > 0)
|
||
+ {
|
||
+ xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
|
||
+ args->note_data = elfcore_write_note (args->obfd, args->note_data,
|
||
+ args->note_size, note_name,
|
||
+ NT_SPU, spu_data, spu_len);
|
||
+ xfree (spu_data);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static char *
|
||
+linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
|
||
+{
|
||
+ struct linux_spu_corefile_data args;
|
||
+ args.obfd = obfd;
|
||
+ args.note_data = note_data;
|
||
+ args.note_size = note_size;
|
||
+
|
||
+ iterate_over_spus (PIDGET (inferior_ptid),
|
||
+ linux_spu_corefile_callback, &args);
|
||
+
|
||
+ return args.note_data;
|
||
+}
|
||
+
|
||
/* Fills the "to_make_corefile_note" target vector. Builds the note
|
||
section for a corefile, and returns it in a malloc buffer. */
|
||
|
||
@@ -3700,6 +3819,8 @@ linux_nat_make_corefile_notes (bfd *obfd
|
||
xfree (auxv);
|
||
}
|
||
|
||
+ note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
|
||
+
|
||
make_cleanup (xfree, note_data);
|
||
return note_data;
|
||
}
|
||
@@ -4031,6 +4152,99 @@ linux_proc_xfer_partial (struct target_o
|
||
return ret;
|
||
}
|
||
|
||
+
|
||
+/* Enumerate spufs IDs for process PID. */
|
||
+static LONGEST
|
||
+spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, LONGEST len)
|
||
+{
|
||
+ LONGEST pos = 0;
|
||
+ LONGEST written = 0;
|
||
+ char path[128];
|
||
+ DIR *dir;
|
||
+ struct dirent *entry;
|
||
+
|
||
+ xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
|
||
+ dir = opendir (path);
|
||
+ if (!dir)
|
||
+ return -1;
|
||
+
|
||
+ rewinddir (dir);
|
||
+ while ((entry = readdir (dir)) != NULL)
|
||
+ {
|
||
+ struct stat st;
|
||
+ struct statfs stfs;
|
||
+ int fd;
|
||
+
|
||
+ fd = atoi (entry->d_name);
|
||
+ if (!fd)
|
||
+ continue;
|
||
+
|
||
+ xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
|
||
+ if (stat (path, &st) != 0)
|
||
+ continue;
|
||
+ if (!S_ISDIR (st.st_mode))
|
||
+ continue;
|
||
+
|
||
+ if (statfs (path, &stfs) != 0)
|
||
+ continue;
|
||
+ if (stfs.f_type != SPUFS_MAGIC)
|
||
+ continue;
|
||
+
|
||
+ if (pos >= offset && pos + 4 <= offset + len)
|
||
+ {
|
||
+ store_unsigned_integer (buf + pos - offset, 4, fd);
|
||
+ written += 4;
|
||
+ }
|
||
+ pos += 4;
|
||
+ }
|
||
+
|
||
+ closedir (dir);
|
||
+ return written;
|
||
+}
|
||
+
|
||
+/* Implement the to_xfer_partial interface for the TARGET_OBJECT_SPU
|
||
+ object type, using the /proc file system. */
|
||
+static LONGEST
|
||
+linux_proc_xfer_spu (struct target_ops *ops, enum target_object object,
|
||
+ const char *annex, gdb_byte *readbuf,
|
||
+ const gdb_byte *writebuf,
|
||
+ ULONGEST offset, LONGEST len)
|
||
+{
|
||
+ char buf[128];
|
||
+ int fd = 0;
|
||
+ int ret = -1;
|
||
+ int pid = PIDGET (inferior_ptid);
|
||
+
|
||
+ if (!annex)
|
||
+ {
|
||
+ if (!readbuf)
|
||
+ return -1;
|
||
+ else
|
||
+ return spu_enumerate_spu_ids (pid, readbuf, offset, len);
|
||
+ }
|
||
+
|
||
+ xsnprintf (buf, sizeof buf, "/proc/%d/fd/%s", pid, annex);
|
||
+ fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
|
||
+ if (fd <= 0)
|
||
+ return -1;
|
||
+
|
||
+ if (offset != 0
|
||
+ && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
|
||
+ {
|
||
+ close (fd);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (writebuf)
|
||
+ ret = write (fd, writebuf, (size_t) len);
|
||
+ else if (readbuf)
|
||
+ ret = read (fd, readbuf, (size_t) len);
|
||
+
|
||
+ close (fd);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+
|
||
/* Parse LINE as a signal set and add its set bits to SIGS. */
|
||
|
||
static void
|
||
@@ -4236,6 +4450,10 @@ linux_xfer_partial (struct target_ops *o
|
||
return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
|
||
offset, len);
|
||
|
||
+ if (object == TARGET_OBJECT_SPU)
|
||
+ return linux_proc_xfer_spu (ops, object, annex, readbuf, writebuf,
|
||
+ offset, len);
|
||
+
|
||
xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
|
||
offset, len);
|
||
if (xfer != 0)
|
||
--- gdb/m32c-tdep.c
|
||
+++ gdb/m32c-tdep.c
|
||
@@ -2401,7 +2401,8 @@ m32c_skip_trampoline_code (struct frame_
|
||
programmer! :) */
|
||
|
||
static void
|
||
-m32c_m16c_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+m32c_m16c_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
enum type_code target_code;
|
||
gdb_assert (TYPE_CODE (type) == TYPE_CODE_PTR ||
|
||
@@ -2449,7 +2450,8 @@ m32c_m16c_address_to_pointer (struct typ
|
||
|
||
|
||
static CORE_ADDR
|
||
-m32c_m16c_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+m32c_m16c_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
{
|
||
CORE_ADDR ptr;
|
||
enum type_code target_code;
|
||
--- gdb/objfiles.c
|
||
+++ gdb/objfiles.c
|
||
@@ -672,7 +672,7 @@ objfile_relocate (struct objfile *objfil
|
||
}
|
||
|
||
/* Relocate breakpoints as necessary, after things are relocated. */
|
||
- breakpoint_re_set ();
|
||
+ breakpoint_relocate (objfile, delta);
|
||
}
|
||
|
||
/* Many places in gdb want to test just to see if we have any partial
|
||
--- gdb/ppc-linux-nat.c
|
||
+++ gdb/ppc-linux-nat.c
|
||
@@ -60,6 +60,9 @@
|
||
If they aren't, we can provide them ourselves (their values are fixed
|
||
because they are part of the kernel ABI). They are used in the AT_HWCAP
|
||
entry of the AUXV. */
|
||
+#ifndef PPC_FEATURE_CELL
|
||
+#define PPC_FEATURE_CELL 0x00010000
|
||
+#endif
|
||
#ifndef PPC_FEATURE_BOOKE
|
||
#define PPC_FEATURE_BOOKE 0x00008000
|
||
#endif
|
||
@@ -1238,12 +1241,58 @@ fill_fpregset (const struct regcache *re
|
||
fpregsetp, sizeof (*fpregsetp));
|
||
}
|
||
|
||
+static int
|
||
+ppc_linux_target_wordsize (void)
|
||
+{
|
||
+ int wordsize = 4;
|
||
+
|
||
+ /* Check for 64-bit inferior process. This is the case when the host is
|
||
+ 64-bit, and in addition the top bit of the MSR register is set. */
|
||
+#ifdef __powerpc64__
|
||
+ long msr;
|
||
+
|
||
+ int tid = TIDGET (inferior_ptid);
|
||
+ if (tid == 0)
|
||
+ tid = PIDGET (inferior_ptid);
|
||
+
|
||
+ errno = 0;
|
||
+ msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
|
||
+ if (errno == 0 && msr < 0)
|
||
+ wordsize = 8;
|
||
+#endif
|
||
+
|
||
+ return wordsize;
|
||
+}
|
||
+
|
||
+static int
|
||
+ppc_linux_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
|
||
+ gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
|
||
+{
|
||
+ int sizeof_auxv_field = ppc_linux_target_wordsize ();
|
||
+ gdb_byte *ptr = *readptr;
|
||
+
|
||
+ if (endptr == ptr)
|
||
+ return 0;
|
||
+
|
||
+ if (endptr - ptr < sizeof_auxv_field * 2)
|
||
+ return -1;
|
||
+
|
||
+ *typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
|
||
+ ptr += sizeof_auxv_field;
|
||
+ *valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
|
||
+ ptr += sizeof_auxv_field;
|
||
+
|
||
+ *readptr = ptr;
|
||
+ return 1;
|
||
+}
|
||
+
|
||
static const struct target_desc *
|
||
ppc_linux_read_description (struct target_ops *ops)
|
||
{
|
||
int altivec = 0;
|
||
int vsx = 0;
|
||
int isa205 = 0;
|
||
+ int cell = 0;
|
||
|
||
int tid = TIDGET (inferior_ptid);
|
||
if (tid == 0)
|
||
@@ -1291,26 +1340,24 @@ ppc_linux_read_description (struct targe
|
||
if (ppc_linux_get_hwcap () & PPC_FEATURE_ARCH_2_05)
|
||
isa205 = 1;
|
||
|
||
- /* Check for 64-bit inferior process. This is the case when the host is
|
||
- 64-bit, and in addition the top bit of the MSR register is set. */
|
||
-#ifdef __powerpc64__
|
||
- {
|
||
- long msr;
|
||
- errno = 0;
|
||
- msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
|
||
- if (errno == 0 && msr < 0)
|
||
- {
|
||
- if (vsx)
|
||
- return isa205? tdesc_powerpc_isa205_vsx64l : tdesc_powerpc_vsx64l;
|
||
- else if (altivec)
|
||
- return isa205? tdesc_powerpc_isa205_altivec64l : tdesc_powerpc_altivec64l;
|
||
+ if (ppc_linux_get_hwcap () & PPC_FEATURE_CELL)
|
||
+ cell = 1;
|
||
|
||
- return isa205? tdesc_powerpc_isa205_64l : tdesc_powerpc_64l;
|
||
- }
|
||
- }
|
||
-#endif
|
||
+ if (ppc_linux_target_wordsize () == 8)
|
||
+ {
|
||
+ if (cell)
|
||
+ return tdesc_powerpc_cell64l;
|
||
+ else if (vsx)
|
||
+ return isa205? tdesc_powerpc_isa205_vsx64l : tdesc_powerpc_vsx64l;
|
||
+ else if (altivec)
|
||
+ return isa205? tdesc_powerpc_isa205_altivec64l : tdesc_powerpc_altivec64l;
|
||
+
|
||
+ return isa205? tdesc_powerpc_isa205_64l : tdesc_powerpc_64l;
|
||
+ }
|
||
|
||
- if (vsx)
|
||
+ if (cell)
|
||
+ return tdesc_powerpc_cell32l;
|
||
+ else if (vsx)
|
||
return isa205? tdesc_powerpc_isa205_vsx32l : tdesc_powerpc_vsx32l;
|
||
else if (altivec)
|
||
return isa205? tdesc_powerpc_isa205_altivec32l : tdesc_powerpc_altivec32l;
|
||
@@ -1342,6 +1389,7 @@ _initialize_ppc_linux_nat (void)
|
||
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
|
||
|
||
t->to_read_description = ppc_linux_read_description;
|
||
+ t->to_auxv_parse = ppc_linux_auxv_parse;
|
||
|
||
/* Register the target. */
|
||
linux_nat_add_target (t);
|
||
--- gdb/ppc-linux-tdep.c
|
||
+++ gdb/ppc-linux-tdep.c
|
||
@@ -38,12 +38,20 @@
|
||
#include "trad-frame.h"
|
||
#include "frame-unwind.h"
|
||
#include "tramp-frame.h"
|
||
+#include "observer.h"
|
||
+#include "auxv.h"
|
||
+#include "elf/common.h"
|
||
+#include "exceptions.h"
|
||
+#include "arch-utils.h"
|
||
+#include "spu-tdep.h"
|
||
|
||
#include "features/rs6000/powerpc-32l.c"
|
||
#include "features/rs6000/powerpc-altivec32l.c"
|
||
+#include "features/rs6000/powerpc-cell32l.c"
|
||
#include "features/rs6000/powerpc-vsx32l.c"
|
||
#include "features/rs6000/powerpc-isa205-32l.c"
|
||
#include "features/rs6000/powerpc-isa205-altivec32l.c"
|
||
+#include "features/rs6000/powerpc-cell64l.c"
|
||
#include "features/rs6000/powerpc-isa205-vsx32l.c"
|
||
#include "features/rs6000/powerpc-64l.c"
|
||
#include "features/rs6000/powerpc-altivec64l.c"
|
||
@@ -995,6 +1003,46 @@ static struct tramp_frame ppc64_linux_si
|
||
};
|
||
|
||
|
||
+/* 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 (¤t_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,
|
||
+ ¤t_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)
|
||
@@ -1028,11 +1076,18 @@ ppc_linux_write_pc (struct regcache *reg
|
||
regcache_cooked_write_unsigned (regcache, PPC_TRAP_REGNUM, -1);
|
||
}
|
||
|
||
+static int
|
||
+ppc_linux_spu_section (bfd *abfd, asection *asect, void *user_data)
|
||
+{
|
||
+ return strncmp (bfd_section_name (abfd, asect), "SPU/", 4) == 0;
|
||
+}
|
||
+
|
||
static const struct target_desc *
|
||
ppc_linux_core_read_description (struct gdbarch *gdbarch,
|
||
struct target_ops *target,
|
||
bfd *abfd)
|
||
{
|
||
+ asection *cell = bfd_sections_find_if (abfd, ppc_linux_spu_section, NULL);
|
||
asection *altivec = bfd_get_section_by_name (abfd, ".reg-ppc-vmx");
|
||
asection *vsx = bfd_get_section_by_name (abfd, ".reg-ppc-vsx");
|
||
asection *section = bfd_get_section_by_name (abfd, ".reg");
|
||
@@ -1042,7 +1097,9 @@ ppc_linux_core_read_description (struct
|
||
switch (bfd_section_size (abfd, section))
|
||
{
|
||
case 48 * 4:
|
||
- if (vsx)
|
||
+ if (cell)
|
||
+ return tdesc_powerpc_cell32l;
|
||
+ else if (vsx)
|
||
return tdesc_powerpc_vsx32l;
|
||
else if (altivec)
|
||
return tdesc_powerpc_altivec32l;
|
||
@@ -1050,7 +1107,9 @@ ppc_linux_core_read_description (struct
|
||
return tdesc_powerpc_32l;
|
||
|
||
case 48 * 8:
|
||
- if (vsx)
|
||
+ if (cell)
|
||
+ return tdesc_powerpc_cell64l;
|
||
+ else if (vsx)
|
||
return tdesc_powerpc_vsx64l;
|
||
else if (altivec)
|
||
return tdesc_powerpc_altivec64l;
|
||
@@ -1062,6 +1121,258 @@ ppc_linux_core_read_description (struct
|
||
}
|
||
}
|
||
|
||
+
|
||
+/* Cell/B.E. active SPE context tracking support. */
|
||
+
|
||
+static CORE_ADDR spe_context_lm_addr = 0;
|
||
+static CORE_ADDR spe_context_offset = 0;
|
||
+
|
||
+static ptid_t spe_context_cache_ptid;
|
||
+static CORE_ADDR spe_context_cache_address;
|
||
+
|
||
+/* Callback for new objfiles. We check whether we've loaded a version
|
||
+ of libspe2 that provides the __spe_current_active_context variable. */
|
||
+static void
|
||
+ppc_linux_new_objfile (struct objfile *objfile)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+
|
||
+ if (!objfile)
|
||
+ {
|
||
+ spe_context_lm_addr = 0;
|
||
+ spe_context_offset = 0;
|
||
+ spe_context_cache_ptid = minus_one_ptid;
|
||
+ spe_context_cache_address = 0;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ sym = lookup_minimal_symbol ("__spe_current_active_context", NULL, objfile);
|
||
+ if (sym)
|
||
+ {
|
||
+ spe_context_lm_addr = svr4_fetch_objfile_link_map (objfile);
|
||
+ spe_context_offset = SYMBOL_VALUE_ADDRESS (sym);
|
||
+ spe_context_cache_ptid = minus_one_ptid;
|
||
+ spe_context_cache_address = 0;
|
||
+ return;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Retrieve contents of the N'th element in the current thread's
|
||
+ linked SPE context list into ID and NPC. Return the address of
|
||
+ said context element, or 0 if not found. */
|
||
+static CORE_ADDR
|
||
+ppc_linux_spe_context (int wordsize, int n, int *id, unsigned int *npc)
|
||
+{
|
||
+ CORE_ADDR spe_context = 0;
|
||
+ gdb_byte buf[16];
|
||
+ int i;
|
||
+
|
||
+ /* Quick exit if we have not found __spe_current_active_context. */
|
||
+ if (!spe_context_lm_addr)
|
||
+ return 0;
|
||
+
|
||
+ /* Look up cached address of thread-local variable. */
|
||
+ if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
|
||
+ {
|
||
+ volatile struct gdb_exception ex;
|
||
+ struct target_ops *target;
|
||
+
|
||
+ for (target = current_target.beneath;
|
||
+ target != NULL;
|
||
+ target = target->beneath)
|
||
+ {
|
||
+ if (target->to_get_thread_local_address != NULL)
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (target == NULL)
|
||
+ return 0;
|
||
+
|
||
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||
+ {
|
||
+ spe_context_cache_address
|
||
+ = target->to_get_thread_local_address
|
||
+ (target, inferior_ptid, spe_context_lm_addr, spe_context_offset);
|
||
+
|
||
+ spe_context_cache_ptid = inferior_ptid;
|
||
+ }
|
||
+
|
||
+ if (ex.reason < 0)
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Read variable value. */
|
||
+ if (target_read_memory (spe_context_cache_address, buf, wordsize) == 0)
|
||
+ spe_context = extract_unsigned_integer (buf, wordsize);
|
||
+
|
||
+ /* Cyle through to N'th linked list element. */
|
||
+ for (i = 0; i < n && spe_context; i++)
|
||
+ if (target_read_memory (spe_context + align_up (12, wordsize),
|
||
+ buf, wordsize) == 0)
|
||
+ spe_context = extract_unsigned_integer (buf, wordsize);
|
||
+ else
|
||
+ spe_context = 0;
|
||
+
|
||
+ /* Read current context. */
|
||
+ if (spe_context
|
||
+ && target_read_memory (spe_context, buf, 12) != 0)
|
||
+ spe_context = 0;
|
||
+
|
||
+ /* Extract data elements. */
|
||
+ if (spe_context)
|
||
+ {
|
||
+ if (id)
|
||
+ *id = extract_signed_integer (buf, 4);
|
||
+ if (npc)
|
||
+ *npc = extract_unsigned_integer (buf + 4, 4);
|
||
+ }
|
||
+
|
||
+ return spe_context;
|
||
+}
|
||
+
|
||
+
|
||
+/* Cell/B.E. cross-architecture unwinder support. */
|
||
+
|
||
+struct ppu2spu_cache
|
||
+{
|
||
+ struct frame_id frame_id;
|
||
+ struct regcache *regcache;
|
||
+};
|
||
+
|
||
+static struct gdbarch *
|
||
+ppu2spu_prev_arch (struct frame_info *this_frame, void **this_cache)
|
||
+{
|
||
+ struct ppu2spu_cache *cache = *this_cache;
|
||
+ return get_regcache_arch (cache->regcache);
|
||
+}
|
||
+
|
||
+static void
|
||
+ppu2spu_this_id (struct frame_info *this_frame,
|
||
+ void **this_cache, struct frame_id *this_id)
|
||
+{
|
||
+ struct ppu2spu_cache *cache = *this_cache;
|
||
+ *this_id = cache->frame_id;
|
||
+}
|
||
+
|
||
+static struct value *
|
||
+ppu2spu_prev_register (struct frame_info *this_frame,
|
||
+ void **this_cache, int regnum)
|
||
+{
|
||
+ struct ppu2spu_cache *cache = *this_cache;
|
||
+ struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
|
||
+ gdb_byte *buf;
|
||
+
|
||
+ buf = alloca (register_size (gdbarch, regnum));
|
||
+ regcache_cooked_read (cache->regcache, regnum, buf);
|
||
+ return frame_unwind_got_bytes (this_frame, regnum, buf);
|
||
+}
|
||
+
|
||
+struct ppu2spu_data
|
||
+{
|
||
+ int id;
|
||
+ unsigned int npc;
|
||
+ gdb_byte gprs[128*16];
|
||
+};
|
||
+
|
||
+static int
|
||
+ppu2spu_unwind_register (void *src, int regnum, gdb_byte *buf)
|
||
+{
|
||
+ struct ppu2spu_data *data = src;
|
||
+
|
||
+ if (regnum >= 0 && regnum < SPU_NUM_GPRS)
|
||
+ memcpy (buf, data->gprs + 16*regnum, 16);
|
||
+ else if (regnum == SPU_ID_REGNUM)
|
||
+ store_unsigned_integer (buf, 4, data->id);
|
||
+ else if (regnum == SPU_PC_REGNUM)
|
||
+ store_unsigned_integer (buf, 4, data->npc);
|
||
+ else
|
||
+ return 0;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static int
|
||
+ppu2spu_sniffer (const struct frame_unwind *self,
|
||
+ struct frame_info *this_frame, void **this_prologue_cache)
|
||
+{
|
||
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
+ struct ppu2spu_data data;
|
||
+ struct frame_info *fi;
|
||
+ CORE_ADDR base, func, backchain, spe_context;
|
||
+ gdb_byte buf[8];
|
||
+ int n = 0;
|
||
+
|
||
+ /* Count the number of SPU contexts already in the frame chain. */
|
||
+ for (fi = get_next_frame (this_frame); fi; fi = get_next_frame (fi))
|
||
+ if (get_frame_type (fi) == ARCH_FRAME
|
||
+ && gdbarch_bfd_arch_info (get_frame_arch (fi))->arch == bfd_arch_spu)
|
||
+ n++;
|
||
+
|
||
+ base = get_frame_sp (this_frame);
|
||
+ func = get_frame_pc (this_frame);
|
||
+ if (target_read_memory (base, buf, tdep->wordsize))
|
||
+ return 0;
|
||
+ backchain = extract_unsigned_integer (buf, tdep->wordsize);
|
||
+
|
||
+ spe_context = ppc_linux_spe_context (tdep->wordsize, n, &data.id, &data.npc);
|
||
+ if (spe_context && base <= spe_context && spe_context < backchain)
|
||
+ {
|
||
+ struct gdbarch *spu_gdbarch;
|
||
+ char annex[32];
|
||
+
|
||
+ /* Find gdbarch for SPU. */
|
||
+ 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 *) &data.id;
|
||
+ spu_gdbarch = gdbarch_find_by_info (info);
|
||
+ if (!spu_gdbarch)
|
||
+ return 0;
|
||
+
|
||
+ xsnprintf (annex, sizeof annex, "%d/regs", data.id);
|
||
+ if (target_read (¤t_target, TARGET_OBJECT_SPU, annex,
|
||
+ data.gprs, 0, sizeof data.gprs)
|
||
+ == sizeof data.gprs)
|
||
+ {
|
||
+ struct ppu2spu_cache *cache
|
||
+ = FRAME_OBSTACK_CALLOC (1, struct ppu2spu_cache);
|
||
+
|
||
+ struct regcache *regcache = regcache_xmalloc (spu_gdbarch);
|
||
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
|
||
+ regcache_save (regcache, ppu2spu_unwind_register, &data);
|
||
+ discard_cleanups (cleanups);
|
||
+
|
||
+ cache->frame_id = frame_id_build (base, func);
|
||
+ cache->regcache = regcache;
|
||
+ *this_prologue_cache = cache;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache)
|
||
+{
|
||
+ struct ppu2spu_cache *cache = this_cache;
|
||
+ regcache_xfree (cache->regcache);
|
||
+}
|
||
+
|
||
+static const struct frame_unwind ppu2spu_unwind = {
|
||
+ ARCH_FRAME,
|
||
+ ppu2spu_this_id,
|
||
+ ppu2spu_prev_register,
|
||
+ NULL,
|
||
+ ppu2spu_sniffer,
|
||
+ ppu2spu_dealloc_cache,
|
||
+ ppu2spu_prev_arch,
|
||
+};
|
||
+
|
||
+
|
||
static void
|
||
ppc_linux_init_abi (struct gdbarch_info info,
|
||
struct gdbarch *gdbarch)
|
||
@@ -1102,6 +1413,12 @@ ppc_linux_init_abi (struct gdbarch_info
|
||
/* Trampolines. */
|
||
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
|
||
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
|
||
+
|
||
+ /* BFD target for core files. */
|
||
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
|
||
+ set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpcle");
|
||
+ else
|
||
+ set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
|
||
}
|
||
|
||
if (tdep->wordsize == 8)
|
||
@@ -1119,6 +1436,12 @@ ppc_linux_init_abi (struct gdbarch_info
|
||
/* Trampolines. */
|
||
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
|
||
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
|
||
+
|
||
+ /* BFD target for core files. */
|
||
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
|
||
+ set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpcle");
|
||
+ else
|
||
+ set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
|
||
}
|
||
set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section);
|
||
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
|
||
@@ -1158,6 +1481,22 @@ ppc_linux_init_abi (struct gdbarch_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);
|
||
+
|
||
+ /* Cell/B.E. cross-architecture unwinder support. */
|
||
+ frame_unwind_prepend_unwinder (gdbarch, &ppu2spu_unwind);
|
||
+
|
||
+ /* 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);
|
||
+ }
|
||
}
|
||
|
||
void
|
||
@@ -1172,15 +1511,23 @@ _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);
|
||
+
|
||
+ /* Add ourselves to objfile event chain. */
|
||
+ observer_attach_new_objfile (ppc_linux_new_objfile);
|
||
+
|
||
/* Initialize the Linux target descriptions. */
|
||
initialize_tdesc_powerpc_32l ();
|
||
initialize_tdesc_powerpc_altivec32l ();
|
||
+ initialize_tdesc_powerpc_cell32l ();
|
||
initialize_tdesc_powerpc_vsx32l ();
|
||
initialize_tdesc_powerpc_isa205_32l ();
|
||
initialize_tdesc_powerpc_isa205_altivec32l ();
|
||
initialize_tdesc_powerpc_isa205_vsx32l ();
|
||
initialize_tdesc_powerpc_64l ();
|
||
initialize_tdesc_powerpc_altivec64l ();
|
||
+ initialize_tdesc_powerpc_cell64l ();
|
||
initialize_tdesc_powerpc_vsx64l ();
|
||
initialize_tdesc_powerpc_isa205_64l ();
|
||
initialize_tdesc_powerpc_isa205_altivec64l ();
|
||
--- gdb/ppc-linux-tdep.h
|
||
+++ gdb/ppc-linux-tdep.h
|
||
@@ -41,6 +41,7 @@ int ppc_linux_trap_reg_p (struct gdbarch
|
||
/* Linux target descriptions. */
|
||
extern struct target_desc *tdesc_powerpc_32l;
|
||
extern struct target_desc *tdesc_powerpc_altivec32l;
|
||
+extern struct target_desc *tdesc_powerpc_cell32l;
|
||
extern struct target_desc *tdesc_powerpc_vsx32l;
|
||
extern struct target_desc *tdesc_powerpc_isa205_32l;
|
||
extern struct target_desc *tdesc_powerpc_isa205_altivec32l;
|
||
@@ -48,6 +49,7 @@ extern struct target_desc *tdesc_powerpc
|
||
extern struct target_desc *tdesc_powerpc_e500l;
|
||
extern struct target_desc *tdesc_powerpc_64l;
|
||
extern struct target_desc *tdesc_powerpc_altivec64l;
|
||
+extern struct target_desc *tdesc_powerpc_cell64l;
|
||
extern struct target_desc *tdesc_powerpc_vsx64l;
|
||
extern struct target_desc *tdesc_powerpc_isa205_64l;
|
||
extern struct target_desc *tdesc_powerpc_isa205_altivec64l;
|
||
--- gdb/printcmd.c
|
||
+++ gdb/printcmd.c
|
||
@@ -388,7 +388,7 @@ print_scalar_formatted (const void *vala
|
||
/* If we are printing it as unsigned, truncate it in case it is actually
|
||
a negative signed value (e.g. "print/u (short)-1" should print 65535
|
||
(if shorts are 16 bits) instead of 4294967295). */
|
||
- if (options->format != 'd')
|
||
+ if (options->format != 'd' || TYPE_UNSIGNED (type))
|
||
{
|
||
if (len < sizeof (LONGEST))
|
||
val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
|
||
--- gdb/proc-service.c
|
||
+++ gdb/proc-service.c
|
||
@@ -258,7 +258,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
|
||
struct regcache *regcache;
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, ph->pid);
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
target_fetch_registers (regcache, -1);
|
||
fill_gregset (regcache, (gdb_gregset_t *) gregset, -1);
|
||
@@ -277,7 +277,7 @@ ps_lsetregs (gdb_ps_prochandle_t ph, lwp
|
||
struct regcache *regcache;
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, ph->pid);
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
supply_gregset (regcache, (const gdb_gregset_t *) gregset);
|
||
target_store_registers (regcache, -1);
|
||
@@ -297,7 +297,7 @@ ps_lgetfpregs (gdb_ps_prochandle_t ph, l
|
||
struct regcache *regcache;
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, ph->pid);
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
target_fetch_registers (regcache, -1);
|
||
fill_fpregset (regcache, (gdb_fpregset_t *) fpregset, -1);
|
||
@@ -317,7 +317,7 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, l
|
||
struct regcache *regcache;
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, ph->pid);
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
|
||
target_store_registers (regcache, -1);
|
||
--- gdb/regcache.c
|
||
+++ gdb/regcache.c
|
||
@@ -29,6 +29,7 @@
|
||
#include "gdb_string.h"
|
||
#include "gdbcmd.h" /* For maintenanceprintlist. */
|
||
#include "observer.h"
|
||
+#include "arch-utils.h"
|
||
|
||
/*
|
||
* DATA STRUCTURE
|
||
@@ -410,36 +411,60 @@ regcache_invalidate (struct regcache *re
|
||
|
||
|
||
/* Global structure containing the current regcache. */
|
||
-/* FIXME: cagney/2002-05-11: The two global arrays registers[] and
|
||
- deprecated_register_valid[] currently point into this structure. */
|
||
-static struct regcache *current_regcache;
|
||
|
||
/* NOTE: this is a write-through cache. There is no "dirty" bit for
|
||
recording if the register values have been changed (eg. by the
|
||
user). Therefore all registers must be written back to the
|
||
target when appropriate. */
|
||
|
||
-struct regcache *get_thread_regcache (ptid_t ptid)
|
||
+struct regcache_list
|
||
{
|
||
- /* NOTE: uweigand/2007-05-05: We need to detect the thread's
|
||
- current architecture at this point. */
|
||
- struct gdbarch *thread_gdbarch = current_gdbarch;
|
||
+ struct regcache *regcache;
|
||
+ struct regcache_list *next;
|
||
+};
|
||
+
|
||
+static struct regcache_list *current_regcache;
|
||
+
|
||
+struct regcache *
|
||
+get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
|
||
+{
|
||
+ struct regcache_list *list;
|
||
+ struct regcache *new_regcache;
|
||
|
||
- if (current_regcache && ptid_equal (current_regcache->ptid, ptid)
|
||
- && get_regcache_arch (current_regcache) == thread_gdbarch)
|
||
- return current_regcache;
|
||
+ for (list = current_regcache; list; list = list->next)
|
||
+ if (ptid_equal (list->regcache->ptid, ptid)
|
||
+ && get_regcache_arch (list->regcache) == gdbarch)
|
||
+ return list->regcache;
|
||
|
||
- if (current_regcache)
|
||
- regcache_xfree (current_regcache);
|
||
+ new_regcache = regcache_xmalloc (gdbarch);
|
||
+ new_regcache->readonly_p = 0;
|
||
+ new_regcache->ptid = ptid;
|
||
|
||
- current_regcache = regcache_xmalloc (thread_gdbarch);
|
||
- current_regcache->readonly_p = 0;
|
||
- current_regcache->ptid = ptid;
|
||
+ list = xmalloc (sizeof (struct regcache_list));
|
||
+ list->regcache = new_regcache;
|
||
+ list->next = current_regcache;
|
||
+ current_regcache = list;
|
||
|
||
- return current_regcache;
|
||
+ return new_regcache;
|
||
}
|
||
|
||
-struct regcache *get_current_regcache (void)
|
||
+static ptid_t current_thread_ptid;
|
||
+static struct gdbarch *current_thread_arch;
|
||
+
|
||
+struct regcache *
|
||
+get_thread_regcache (ptid_t ptid)
|
||
+{
|
||
+ if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid))
|
||
+ {
|
||
+ current_thread_ptid = ptid;
|
||
+ current_thread_arch = target_thread_architecture (ptid);
|
||
+ }
|
||
+
|
||
+ return get_thread_arch_regcache (ptid, current_thread_arch);
|
||
+}
|
||
+
|
||
+struct regcache *
|
||
+get_current_regcache (void)
|
||
{
|
||
return get_thread_regcache (inferior_ptid);
|
||
}
|
||
@@ -458,9 +483,11 @@ regcache_observer_target_changed (struct
|
||
static void
|
||
regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
||
{
|
||
- if (current_regcache != NULL
|
||
- && ptid_equal (current_regcache->ptid, old_ptid))
|
||
- current_regcache->ptid = new_ptid;
|
||
+ struct regcache_list *list;
|
||
+
|
||
+ for (list = current_regcache; list; list = list->next)
|
||
+ if (ptid_equal (list->regcache->ptid, old_ptid))
|
||
+ list->regcache->ptid = new_ptid;
|
||
}
|
||
|
||
/* Low level examining and depositing of registers.
|
||
@@ -477,11 +504,20 @@ regcache_thread_ptid_changed (ptid_t old
|
||
void
|
||
registers_changed (void)
|
||
{
|
||
- int i;
|
||
+ struct regcache_list *list, *next;
|
||
+
|
||
+ for (list = current_regcache; list; list = next)
|
||
+ {
|
||
+ next = list->next;
|
||
+ regcache_xfree (list->regcache);
|
||
+ xfree (list);
|
||
+ }
|
||
|
||
- regcache_xfree (current_regcache);
|
||
current_regcache = NULL;
|
||
|
||
+ current_thread_ptid = null_ptid;
|
||
+ current_thread_arch = NULL;
|
||
+
|
||
/* Need to forget about any frames we have cached, too. */
|
||
reinit_frame_cache ();
|
||
|
||
@@ -509,6 +545,8 @@ regcache_raw_read (struct regcache *regc
|
||
{
|
||
struct cleanup *old_chain = save_inferior_ptid ();
|
||
inferior_ptid = regcache->ptid;
|
||
+ save_current_gdbarch ();
|
||
+ current_gdbarch = get_regcache_arch (regcache);
|
||
target_fetch_registers (regcache, regnum);
|
||
do_cleanups (old_chain);
|
||
}
|
||
@@ -667,6 +705,8 @@ regcache_raw_write (struct regcache *reg
|
||
|
||
old_chain = save_inferior_ptid ();
|
||
inferior_ptid = regcache->ptid;
|
||
+ save_current_gdbarch ();
|
||
+ current_gdbarch = get_regcache_arch (regcache);
|
||
|
||
target_prepare_to_store (regcache);
|
||
memcpy (register_buffer (regcache, regnum), buf,
|
||
--- gdb/regcache.h
|
||
+++ gdb/regcache.h
|
||
@@ -26,6 +26,7 @@ struct gdbarch;
|
||
|
||
extern struct regcache *get_current_regcache (void);
|
||
extern struct regcache *get_thread_regcache (ptid_t ptid);
|
||
+extern struct regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *);
|
||
|
||
void regcache_xfree (struct regcache *regcache);
|
||
struct cleanup *make_cleanup_regcache_xfree (struct regcache *regcache);
|
||
--- gdb/regformats/rs6000/powerpc-cell32l.dat
|
||
+++ gdb/regformats/rs6000/powerpc-cell32l.dat
|
||
@@ -0,0 +1,111 @@
|
||
+# DO NOT EDIT: generated from rs6000/powerpc-cell32l.xml
|
||
+name:powerpc_cell32l
|
||
+xmltarget:powerpc-cell32l.xml
|
||
+expedite:r1,pc,r0,orig_r3,r4
|
||
+32:r0
|
||
+32:r1
|
||
+32:r2
|
||
+32:r3
|
||
+32:r4
|
||
+32:r5
|
||
+32:r6
|
||
+32:r7
|
||
+32:r8
|
||
+32:r9
|
||
+32:r10
|
||
+32:r11
|
||
+32:r12
|
||
+32:r13
|
||
+32:r14
|
||
+32:r15
|
||
+32:r16
|
||
+32:r17
|
||
+32:r18
|
||
+32:r19
|
||
+32:r20
|
||
+32:r21
|
||
+32:r22
|
||
+32:r23
|
||
+32:r24
|
||
+32:r25
|
||
+32:r26
|
||
+32:r27
|
||
+32:r28
|
||
+32:r29
|
||
+32:r30
|
||
+32:r31
|
||
+64:f0
|
||
+64:f1
|
||
+64:f2
|
||
+64:f3
|
||
+64:f4
|
||
+64:f5
|
||
+64:f6
|
||
+64:f7
|
||
+64:f8
|
||
+64:f9
|
||
+64:f10
|
||
+64:f11
|
||
+64:f12
|
||
+64:f13
|
||
+64:f14
|
||
+64:f15
|
||
+64:f16
|
||
+64:f17
|
||
+64:f18
|
||
+64:f19
|
||
+64:f20
|
||
+64:f21
|
||
+64:f22
|
||
+64:f23
|
||
+64:f24
|
||
+64:f25
|
||
+64:f26
|
||
+64:f27
|
||
+64:f28
|
||
+64:f29
|
||
+64:f30
|
||
+64:f31
|
||
+32:pc
|
||
+32:msr
|
||
+32:cr
|
||
+32:lr
|
||
+32:ctr
|
||
+32:xer
|
||
+32:fpscr
|
||
+32:orig_r3
|
||
+32:trap
|
||
+128:vr0
|
||
+128:vr1
|
||
+128:vr2
|
||
+128:vr3
|
||
+128:vr4
|
||
+128:vr5
|
||
+128:vr6
|
||
+128:vr7
|
||
+128:vr8
|
||
+128:vr9
|
||
+128:vr10
|
||
+128:vr11
|
||
+128:vr12
|
||
+128:vr13
|
||
+128:vr14
|
||
+128:vr15
|
||
+128:vr16
|
||
+128:vr17
|
||
+128:vr18
|
||
+128:vr19
|
||
+128:vr20
|
||
+128:vr21
|
||
+128:vr22
|
||
+128:vr23
|
||
+128:vr24
|
||
+128:vr25
|
||
+128:vr26
|
||
+128:vr27
|
||
+128:vr28
|
||
+128:vr29
|
||
+128:vr30
|
||
+128:vr31
|
||
+32:vscr
|
||
+32:vrsave
|
||
--- gdb/regformats/rs6000/powerpc-cell64l.dat
|
||
+++ gdb/regformats/rs6000/powerpc-cell64l.dat
|
||
@@ -0,0 +1,111 @@
|
||
+# DO NOT EDIT: generated from rs6000/powerpc-cell64l.xml
|
||
+name:powerpc_cell64l
|
||
+xmltarget:powerpc-cell64l.xml
|
||
+expedite:r1,pc,r0,orig_r3,r4
|
||
+64:r0
|
||
+64:r1
|
||
+64:r2
|
||
+64:r3
|
||
+64:r4
|
||
+64:r5
|
||
+64:r6
|
||
+64:r7
|
||
+64:r8
|
||
+64:r9
|
||
+64:r10
|
||
+64:r11
|
||
+64:r12
|
||
+64:r13
|
||
+64:r14
|
||
+64:r15
|
||
+64:r16
|
||
+64:r17
|
||
+64:r18
|
||
+64:r19
|
||
+64:r20
|
||
+64:r21
|
||
+64:r22
|
||
+64:r23
|
||
+64:r24
|
||
+64:r25
|
||
+64:r26
|
||
+64:r27
|
||
+64:r28
|
||
+64:r29
|
||
+64:r30
|
||
+64:r31
|
||
+64:f0
|
||
+64:f1
|
||
+64:f2
|
||
+64:f3
|
||
+64:f4
|
||
+64:f5
|
||
+64:f6
|
||
+64:f7
|
||
+64:f8
|
||
+64:f9
|
||
+64:f10
|
||
+64:f11
|
||
+64:f12
|
||
+64:f13
|
||
+64:f14
|
||
+64:f15
|
||
+64:f16
|
||
+64:f17
|
||
+64:f18
|
||
+64:f19
|
||
+64:f20
|
||
+64:f21
|
||
+64:f22
|
||
+64:f23
|
||
+64:f24
|
||
+64:f25
|
||
+64:f26
|
||
+64:f27
|
||
+64:f28
|
||
+64:f29
|
||
+64:f30
|
||
+64:f31
|
||
+64:pc
|
||
+64:msr
|
||
+32:cr
|
||
+64:lr
|
||
+64:ctr
|
||
+32:xer
|
||
+32:fpscr
|
||
+64:orig_r3
|
||
+64:trap
|
||
+128:vr0
|
||
+128:vr1
|
||
+128:vr2
|
||
+128:vr3
|
||
+128:vr4
|
||
+128:vr5
|
||
+128:vr6
|
||
+128:vr7
|
||
+128:vr8
|
||
+128:vr9
|
||
+128:vr10
|
||
+128:vr11
|
||
+128:vr12
|
||
+128:vr13
|
||
+128:vr14
|
||
+128:vr15
|
||
+128:vr16
|
||
+128:vr17
|
||
+128:vr18
|
||
+128:vr19
|
||
+128:vr20
|
||
+128:vr21
|
||
+128:vr22
|
||
+128:vr23
|
||
+128:vr24
|
||
+128:vr25
|
||
+128:vr26
|
||
+128:vr27
|
||
+128:vr28
|
||
+128:vr29
|
||
+128:vr30
|
||
+128:vr31
|
||
+32:vscr
|
||
+32:vrsave
|
||
--- gdb/remote.c
|
||
+++ gdb/remote.c
|
||
@@ -4526,7 +4526,7 @@ process_stop_reply (struct stop_reply *s
|
||
for (ix = 0;
|
||
VEC_iterate(cached_reg_t, stop_reply->regcache, ix, reg);
|
||
ix++)
|
||
- regcache_raw_supply (get_thread_regcache (ptid),
|
||
+ regcache_raw_supply (get_thread_arch_regcache (ptid, target_gdbarch),
|
||
reg->num, reg->data);
|
||
VEC_free (cached_reg_t, stop_reply->regcache);
|
||
}
|
||
@@ -6785,7 +6785,7 @@ remote_insert_breakpoint (struct bp_targ
|
||
switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_Z0]))
|
||
{
|
||
case PACKET_ERROR:
|
||
- return -1;
|
||
+ return 1;
|
||
case PACKET_OK:
|
||
bp_tgt->placed_address = addr;
|
||
bp_tgt->placed_size = bpsize;
|
||
@@ -6972,7 +6972,7 @@ remote_insert_hw_breakpoint (struct bp_t
|
||
(target_gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
|
||
|
||
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
|
||
- return -1;
|
||
+ return 1;
|
||
|
||
rs = get_remote_state ();
|
||
p = rs->buf;
|
||
@@ -6992,7 +6992,7 @@ remote_insert_hw_breakpoint (struct bp_t
|
||
{
|
||
case PACKET_ERROR:
|
||
case PACKET_UNKNOWN:
|
||
- return -1;
|
||
+ return 1;
|
||
case PACKET_OK:
|
||
return 0;
|
||
}
|
||
@@ -7009,7 +7009,7 @@ remote_remove_hw_breakpoint (struct bp_t
|
||
char *p = rs->buf;
|
||
|
||
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
|
||
- return -1;
|
||
+ return 1;
|
||
|
||
*(p++) = 'z';
|
||
*(p++) = '1';
|
||
@@ -7026,7 +7026,7 @@ remote_remove_hw_breakpoint (struct bp_t
|
||
{
|
||
case PACKET_ERROR:
|
||
case PACKET_UNKNOWN:
|
||
- return -1;
|
||
+ return 1;
|
||
case PACKET_OK:
|
||
return 0;
|
||
}
|
||
--- gdb/rs6000-tdep.c
|
||
+++ gdb/rs6000-tdep.c
|
||
@@ -3338,6 +3338,16 @@ rs6000_gdbarch_init (struct gdbarch_info
|
||
int num_pseudoregs = 0;
|
||
int cur_reg;
|
||
|
||
+ /* INFO may refer to a binary that is not of the PowerPC architecture,
|
||
+ e.g. when debugging a stand-alone SPE executable on a Cell/B.E. system.
|
||
+ In this case, we must not attempt to infer properties of the (PowerPC
|
||
+ side) of the target system from properties of that executable. Trust
|
||
+ the target description instead. */
|
||
+ if (info.abfd
|
||
+ && bfd_get_arch (info.abfd) != bfd_arch_powerpc
|
||
+ && bfd_get_arch (info.abfd) != bfd_arch_rs6000)
|
||
+ info.abfd = NULL;
|
||
+
|
||
from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
|
||
bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
|
||
|
||
--- gdb/sentinel-frame.c
|
||
+++ gdb/sentinel-frame.c
|
||
@@ -76,11 +76,23 @@ sentinel_frame_this_id (struct frame_inf
|
||
internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
|
||
}
|
||
|
||
+static struct gdbarch *
|
||
+sentinel_frame_prev_arch (struct frame_info *this_frame,
|
||
+ void **this_prologue_cache)
|
||
+{
|
||
+ struct frame_unwind_cache *cache = *this_prologue_cache;
|
||
+ return get_regcache_arch (cache->regcache);
|
||
+}
|
||
+
|
||
const struct frame_unwind sentinel_frame_unwinder =
|
||
{
|
||
SENTINEL_FRAME,
|
||
sentinel_frame_this_id,
|
||
- sentinel_frame_prev_register
|
||
+ sentinel_frame_prev_register,
|
||
+ NULL,
|
||
+ NULL,
|
||
+ NULL,
|
||
+ sentinel_frame_prev_arch,
|
||
};
|
||
|
||
const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
|
||
--- gdb/sol-thread.c
|
||
+++ gdb/sol-thread.c
|
||
@@ -1094,7 +1094,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
|
||
old_chain = save_inferior_ptid ();
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
if (target_has_execution)
|
||
procfs_ops.to_fetch_registers (regcache, -1);
|
||
@@ -1119,7 +1119,7 @@ ps_lsetregs (gdb_ps_prochandle_t ph, lwp
|
||
old_chain = save_inferior_ptid ();
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
supply_gregset (regcache, (const gdb_gregset_t *) gregset);
|
||
if (target_has_execution)
|
||
@@ -1230,7 +1230,7 @@ ps_lgetfpregs (gdb_ps_prochandle_t ph, l
|
||
old_chain = save_inferior_ptid ();
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
if (target_has_execution)
|
||
procfs_ops.to_fetch_registers (regcache, -1);
|
||
@@ -1255,7 +1255,7 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, l
|
||
old_chain = save_inferior_ptid ();
|
||
|
||
inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
|
||
- regcache = get_thread_regcache (inferior_ptid);
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
|
||
supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
|
||
if (target_has_execution)
|
||
--- gdb/solib-spu.c
|
||
+++ gdb/solib-spu.c
|
||
@@ -0,0 +1,482 @@
|
||
+/* Cell SPU GNU/Linux support -- shared library handling.
|
||
+ Copyright (C) 2008 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 "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 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)
|
||
+ {
|
||
+ struct cleanup *old_chain;
|
||
+ struct inferior *inferior = current_inferior ();
|
||
+
|
||
+ /* Suppress MI messages that are unexpected at this point. */
|
||
+ old_chain = make_cleanup_restore_integer (&suppress_resume_observer);
|
||
+ suppress_resume_observer = 1;
|
||
+ make_cleanup_restore_integer (&suppress_stop_observer);
|
||
+ suppress_stop_observer = 1;
|
||
+
|
||
+ /* 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->stop_soon = STOP_QUIETLY;
|
||
+ resume (1, TARGET_SIGNAL_0);
|
||
+ wait_for_inferior (1);
|
||
+ inferior->stop_soon = NO_STOP_QUIETLY;
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 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)
|
||
+{
|
||
+ 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. Switch to the
|
||
+ PPE architecture while doing so. This should not be strictly
|
||
+ necessary, but it is right now. */
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ head = svr4_so_ops.current_sos ();
|
||
+ do_cleanups (old_chain);
|
||
+
|
||
+ /* 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 (¤t_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)
|
||
+ spu_relocate_main_executable (extract_unsigned_integer (buf, 4));
|
||
+
|
||
+ return head;
|
||
+ }
|
||
+
|
||
+ /* As soon as any SPE context exists in the inferior, we have to
|
||
+ enable SPU multi-architecture target support. */
|
||
+ if (size > 0)
|
||
+ spu_multiarch_enable ();
|
||
+ else
|
||
+ spu_multiarch_disable ();
|
||
+
|
||
+ /* Create an so_list entry for each SPU id. */
|
||
+ for (i = 0; i < size; i += 4)
|
||
+ {
|
||
+ int fd = extract_unsigned_integer (buf + i, 4);
|
||
+ 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 (¤t_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 section_table *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;
|
||
+
|
||
+ /* Switch to the PPE architecture while reading target memory.
|
||
+ This should not be necessary, but it is right now. */
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ ret = target_read_memory (addr + offset, buf, nbytes);
|
||
+ do_cleanups (old_chain);
|
||
+
|
||
+ 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_open (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_open_bfd (char *pathname)
|
||
+{
|
||
+ char *original_name = strrchr (pathname, '@');
|
||
+ char name[64];
|
||
+ bfd *abfd;
|
||
+ asection *spu_name;
|
||
+ unsigned long long addr;
|
||
+ int fd;
|
||
+
|
||
+ if (!original_name)
|
||
+ return NULL;
|
||
+
|
||
+ /* 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_open (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,
|
||
+ ¤t_target);
|
||
+ create_solib_event_breakpoint (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 ();
|
||
+
|
||
+ /* At this point, the target is executing, so GDB expects to be
|
||
+ able to read/write target memory. For the stand-alone case,
|
||
+ "target memory" is actually the local store of the stand-alone
|
||
+ SPE context -- but at this point this context has not yet been
|
||
+ allocated. This is a problem in particular for breakpoints that
|
||
+ may already have been established.
|
||
+
|
||
+ We solve this by installing the multi-architecture handler
|
||
+ already at this point. This target will understand that
|
||
+ breakpoints falling the range of addresses covered by the
|
||
+ SPE local store need to be ignored.
|
||
+
|
||
+ (Note that this needs to be done here, before the solib code gets
|
||
+ active -- otherwise we'd fail on the first breakpoint_re_set call
|
||
+ triggered when new shared libraries are found.)
|
||
+
|
||
+ Once the actual stand-alone SPE context is installed, spu_current_sos
|
||
+ will detect this and relocate the main executable to its final (valid)
|
||
+ address range. Breakpoints will be automatically re-inserted at
|
||
+ that point. */
|
||
+ spu_multiarch_enable ();
|
||
+
|
||
+ /* 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.open_bfd = spu_open_bfd;
|
||
+ 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);
|
||
+ spu_enable_break (so->objfile);
|
||
+ }
|
||
+}
|
||
+
|
||
+void
|
||
+_initialize_spu_solib (void)
|
||
+{
|
||
+ observer_attach_solib_loaded (spu_solib_loaded);
|
||
+}
|
||
+
|
||
--- gdb/solib.c
|
||
+++ gdb/solib.c
|
||
@@ -345,15 +345,22 @@ static int
|
||
solib_map_sections (void *arg)
|
||
{
|
||
struct so_list *so = (struct so_list *) arg; /* catch_errors bogon */
|
||
+ struct target_so_ops *ops = solib_ops (target_gdbarch);
|
||
char *filename;
|
||
struct section_table *p;
|
||
struct cleanup *old_chain;
|
||
- bfd *abfd;
|
||
+ bfd *abfd = NULL;
|
||
+
|
||
+ if (ops->open_bfd)
|
||
+ abfd = ops->open_bfd (so->so_name);
|
||
|
||
- filename = tilde_expand (so->so_name);
|
||
- old_chain = make_cleanup (xfree, filename);
|
||
- abfd = solib_bfd_open (filename);
|
||
- do_cleanups (old_chain);
|
||
+ if (!abfd)
|
||
+ {
|
||
+ filename = tilde_expand (so->so_name);
|
||
+ old_chain = make_cleanup (xfree, filename);
|
||
+ abfd = solib_bfd_open (filename);
|
||
+ do_cleanups (old_chain);
|
||
+ }
|
||
|
||
/* Leave bfd open, core_xfer_memory and "info files" need it. */
|
||
so->abfd = abfd;
|
||
@@ -372,8 +379,6 @@ solib_map_sections (void *arg)
|
||
|
||
for (p = so->sections; p < so->sections_end; p++)
|
||
{
|
||
- struct target_so_ops *ops = solib_ops (target_gdbarch);
|
||
-
|
||
/* Relocate the section binding addresses as recorded in the shared
|
||
object's file by the base address to which the object was actually
|
||
mapped. */
|
||
@@ -454,7 +459,9 @@ static int
|
||
symbol_add_stub (void *arg)
|
||
{
|
||
struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
|
||
+ struct target_so_ops *ops = solib_ops (target_gdbarch);
|
||
struct section_addr_info *sap;
|
||
+ bfd *abfd = NULL;
|
||
|
||
/* Have we already loaded this shared object? */
|
||
ALL_OBJFILES (so->objfile)
|
||
--- gdb/solist.h
|
||
+++ gdb/solist.h
|
||
@@ -123,6 +123,10 @@ struct target_so_ops
|
||
Falls back to using strcmp on so_original_name field when set
|
||
to NULL. */
|
||
int (*same) (struct so_list *gdb, struct so_list *inferior);
|
||
+
|
||
+ /* Extra hook for opening a BFD for a solib. Can be used to
|
||
+ retrieve solibs from inferior memory instead of from files. */
|
||
+ bfd *(*open_bfd) (char *pathname);
|
||
};
|
||
|
||
/* Free the memory associated with a (so_list *). */
|
||
--- gdb/spu-multiarch.c
|
||
+++ gdb/spu-multiarch.c
|
||
@@ -0,0 +1,462 @@
|
||
+/* Cell SPU GNU/Linux multi-architecture debugging support.
|
||
+ Copyright (C) 2008 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 "block.h"
|
||
+#include "exec.h"
|
||
+#include "target-descriptions.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;
|
||
+
|
||
+/* 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)
|
||
+{
|
||
+ 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) != INSTR_SC)
|
||
+ return 0;
|
||
+ /* System call number should be NR_spu_run. */
|
||
+ regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum, ®val);
|
||
+ 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, ®val);
|
||
+ *fd = (int) regval;
|
||
+ regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 4, ®val);
|
||
+ *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_wait routine to detect current architecture. */
|
||
+static ptid_t
|
||
+spu_wait (struct target_ops *ops, ptid_t ptid,
|
||
+ struct target_waitstatus *ourstatus)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (ops);
|
||
+
|
||
+ /* Always switch to PPU while running the inferior. This allows
|
||
+ linux-thread-db.c code to work as expected. */
|
||
+ current_gdbarch = target_gdbarch;
|
||
+
|
||
+ /* Run it. */
|
||
+ ptid = ops_beneath->to_wait (ops_beneath, ptid, ourstatus);
|
||
+
|
||
+ /* Detect and switch to current architecture. */
|
||
+ if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
|
||
+ current_gdbarch = spu_thread_architecture (¤t_target, ptid);
|
||
+
|
||
+ return ptid;
|
||
+}
|
||
+
|
||
+
|
||
+/* 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);
|
||
+ gdb_assert (ops_beneath);
|
||
+
|
||
+ /* Ignore attempts to remove breakpoints in a stand-alone SPE
|
||
+ executable just after startup, before we know the FD. */
|
||
+ if (spu_standalone_p () && addr < SPU_LS_SIZE)
|
||
+ return -1;
|
||
+
|
||
+ /* 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_insert_breakpoint routine. */
|
||
+static int
|
||
+spu_insert_breakpoint (struct bp_target_info *bp)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
|
||
+ CORE_ADDR addr = bp->placed_address;
|
||
+ struct cleanup *old_chain;
|
||
+ int ret;
|
||
+
|
||
+ while (ops_beneath && !ops_beneath->to_insert_breakpoint)
|
||
+ ops_beneath = find_target_beneath (ops_beneath);
|
||
+ gdb_assert (ops_beneath);
|
||
+
|
||
+ /* Ignore attempts to insert breakpoints in a stand-alone SPE
|
||
+ executable just after startup, before we know the FD. */
|
||
+ if (spu_standalone_p () && addr < SPU_LS_SIZE)
|
||
+ return -1;
|
||
+
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ if (SPUADDR_SPU (addr) != -1)
|
||
+ current_gdbarch = spu_gdbarch (SPUADDR_SPU (addr));
|
||
+ else
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ ret = ops_beneath->to_insert_breakpoint (bp);
|
||
+ do_cleanups (old_chain);
|
||
+
|
||
+ /* Ignore failure to insert breakpoints in a stand-alone SPE
|
||
+ executable just before exit, when the FD is already gone. */
|
||
+ if (spu_standalone_p () && ret > 0)
|
||
+ ret = -1;
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+/* Override the to_remove_breakpoint routine. */
|
||
+static int
|
||
+spu_remove_breakpoint (struct bp_target_info *bp)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
|
||
+ CORE_ADDR addr = bp->placed_address;
|
||
+ struct cleanup *old_chain;
|
||
+ int ret;
|
||
+
|
||
+ while (ops_beneath && !ops_beneath->to_remove_breakpoint)
|
||
+ ops_beneath = find_target_beneath (ops_beneath);
|
||
+ gdb_assert (ops_beneath);
|
||
+
|
||
+ /* Ignore attempts to remove breakpoints in a stand-alone SPE
|
||
+ executable just after startup, before we know the FD. */
|
||
+ if (spu_standalone_p () && addr < SPU_LS_SIZE)
|
||
+ return -1;
|
||
+
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ if (SPUADDR_SPU (addr) != -1)
|
||
+ current_gdbarch = spu_gdbarch (SPUADDR_SPU (addr));
|
||
+ else
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ ret = ops_beneath->to_remove_breakpoint (bp);
|
||
+ do_cleanups (old_chain);
|
||
+
|
||
+ /* Ignore failure to remove breakpoints in a stand-alone SPE
|
||
+ executable just before exit, when the FD is already gone. */
|
||
+ if (spu_standalone_p () && ret > 0)
|
||
+ ret = -1;
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+
|
||
+/* Override the to_fetch_registers routine. */
|
||
+static void
|
||
+spu_fetch_registers (struct regcache *regcache, int regno)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
|
||
+ int spufs_fd;
|
||
+ CORE_ADDR spufs_addr;
|
||
+
|
||
+ /* This version applies only if we're currently in spu_run. */
|
||
+ if (gdbarch_bfd_arch_info (get_regcache_arch (regcache))->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 (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, 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)
|
||
+ {
|
||
+ struct cleanup *old_chain;
|
||
+ LONGEST ret;
|
||
+ char buf[4];
|
||
+
|
||
+ /* Switch to PPC arch while accessing target memory. */
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ ret = target_read (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
|
||
+ buf, spufs_addr, sizeof buf);
|
||
+ do_cleanups (old_chain);
|
||
+
|
||
+ if (ret == 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 regcache *regcache, int regno)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
|
||
+ int spufs_fd;
|
||
+ CORE_ADDR spufs_addr;
|
||
+
|
||
+ /* This version applies only if we're currently in spu_run. */
|
||
+ if (gdbarch_bfd_arch_info (get_regcache_arch (regcache))->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 (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)
|
||
+ {
|
||
+ struct cleanup *old_chain;
|
||
+ char buf[4];
|
||
+ regcache_raw_collect (regcache, SPU_PC_REGNUM, buf);
|
||
+
|
||
+ /* Switch to PPC arch while accessing target memory. */
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = target_gdbarch;
|
||
+ target_write (ops_beneath, TARGET_OBJECT_MEMORY, NULL,
|
||
+ buf, spufs_addr, sizeof buf);
|
||
+ do_cleanups (old_chain);
|
||
+ }
|
||
+
|
||
+ /* 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);
|
||
+
|
||
+ /* 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. */
|
||
+
|
||
+void
|
||
+spu_multiarch_enable (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);
|
||
+}
|
||
+
|
||
+void
|
||
+spu_multiarch_disable (void)
|
||
+{
|
||
+ unpush_target (&spu_ops);
|
||
+}
|
||
+
|
||
+static void
|
||
+spu_mourn_inferior (struct target_ops *ops)
|
||
+{
|
||
+ struct target_ops *ops_beneath = find_target_beneath (ops);
|
||
+ ops_beneath->to_mourn_inferior (ops_beneath);
|
||
+ spu_multiarch_disable ();
|
||
+}
|
||
+
|
||
+
|
||
+/* 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_insert_breakpoint = spu_insert_breakpoint;
|
||
+ spu_ops.to_remove_breakpoint = spu_remove_breakpoint;
|
||
+ spu_ops.to_region_ok_for_hw_watchpoint = spu_region_ok_for_hw_watchpoint;
|
||
+ spu_ops.to_wait = spu_wait;
|
||
+ 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);
|
||
+}
|
||
+
|
||
--- gdb/spu-tdep.c
|
||
+++ gdb/spu-tdep.c
|
||
@@ -40,14 +40,31 @@
|
||
#include "regcache.h"
|
||
#include "reggroups.h"
|
||
#include "floatformat.h"
|
||
+#include "block.h"
|
||
#include "observer.h"
|
||
+#include "infcall.h"
|
||
|
||
#include "spu-tdep.h"
|
||
|
||
|
||
+/* The list of available "set spu " and "show spu " commands. */
|
||
+static struct cmd_list_element *setspucmdlist = NULL;
|
||
+static struct cmd_list_element *showspucmdlist = NULL;
|
||
+
|
||
+/* Whether to stop for new SPE contexts. */
|
||
+static int spu_stop_on_load_p = 0;
|
||
+/* Whether to automatically flush the SW-managed cache. */
|
||
+static int spu_auto_flush_cache_p = 1;
|
||
+
|
||
+
|
||
/* The tdep structure. */
|
||
struct gdbarch_tdep
|
||
{
|
||
+ /* The spufs ID identifying our address space. */
|
||
+ int id;
|
||
+ /* The size of this address space. */
|
||
+ CORE_ADDR lslr;
|
||
+
|
||
/* SPU-specific vector type. */
|
||
struct type *spu_builtin_type_vec128;
|
||
};
|
||
@@ -324,33 +341,87 @@ spu_register_reggroup_p (struct gdbarch
|
||
return default_register_reggroup_p (gdbarch, regnum, group);
|
||
}
|
||
|
||
-/* Address conversion. */
|
||
+
|
||
+/* Address handling. */
|
||
|
||
static CORE_ADDR
|
||
-spu_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+spu_lslr (int id)
|
||
{
|
||
+ gdb_byte buf[16];
|
||
+ char annex[32];
|
||
+
|
||
+ xsnprintf (annex, sizeof annex, "%d/lslr", id);
|
||
+ memset (buf, 0, sizeof buf);
|
||
+ target_read (¤t_target, TARGET_OBJECT_SPU, annex,
|
||
+ buf, 0, sizeof buf);
|
||
+
|
||
+ return strtoulst (buf, NULL, 16);
|
||
+}
|
||
+
|
||
+static int
|
||
+spu_address_class_type_flags (int byte_size, int dwarf2_addr_class)
|
||
+{
|
||
+ if (dwarf2_addr_class == 1)
|
||
+ return TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
|
||
+ else
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static const char *
|
||
+spu_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags)
|
||
+{
|
||
+ if (type_flags & TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1)
|
||
+ return "__ea";
|
||
+ else
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static int
|
||
+spu_address_class_name_to_type_flags (struct gdbarch *gdbarch,
|
||
+ const char *name, int *type_flags_ptr)
|
||
+{
|
||
+ if (strcmp (name, "__ea") == 0)
|
||
+ {
|
||
+ *type_flags_ptr = TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1;
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+spu_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+{
|
||
+ store_unsigned_integer (buf, TYPE_LENGTH (type), SPUADDR_ADDR (addr));
|
||
+}
|
||
+
|
||
+static CORE_ADDR
|
||
+spu_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
+{
|
||
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
ULONGEST addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
|
||
- 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);
|
||
+ /* Do not convert __ea pointers. */
|
||
+ if (TYPE_ADDRESS_CLASS_1 (type))
|
||
+ return addr;
|
||
|
||
- return addr & lslr;
|
||
+ return addr? SPUADDR (tdep->id, addr & tdep->lslr) : 0;
|
||
}
|
||
|
||
static CORE_ADDR
|
||
spu_integer_to_address (struct gdbarch *gdbarch,
|
||
struct type *type, const gdb_byte *buf)
|
||
{
|
||
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
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);
|
||
+ /* Do not convert __ea pointers. */
|
||
+ if (TYPE_ADDRESS_CLASS_1 (type))
|
||
+ return addr;
|
||
|
||
- return addr & lslr;
|
||
+ return SPUADDR (tdep->id, addr & tdep->lslr);
|
||
}
|
||
|
||
|
||
@@ -840,8 +911,11 @@ static struct spu_unwind_cache *
|
||
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);
|
||
struct spu_unwind_cache *info;
|
||
struct spu_prologue_data data;
|
||
+ CORE_ADDR id = tdep->id;
|
||
gdb_byte buf[16];
|
||
|
||
if (*this_prologue_cache)
|
||
@@ -874,6 +948,7 @@ spu_frame_unwind_cache (struct frame_inf
|
||
/* Determine CFA via unwound CFA_REG plus CFA_OFFSET. */
|
||
get_frame_register (this_frame, data.cfa_reg, buf);
|
||
cfa = extract_unsigned_integer (buf, 4) + data.cfa_offset;
|
||
+ cfa = SPUADDR (id, cfa);
|
||
|
||
/* Call-saved register slots. */
|
||
for (i = 0; i < SPU_NUM_GPRS; i++)
|
||
@@ -896,7 +971,7 @@ spu_frame_unwind_cache (struct frame_inf
|
||
|
||
/* Get the backchain. */
|
||
reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
|
||
- status = safe_read_memory_integer (reg, 4, &backchain);
|
||
+ status = safe_read_memory_integer (SPUADDR (id, reg), 4, &backchain);
|
||
|
||
/* A zero backchain terminates the frame chain. Also, sanity
|
||
check against the local store size limit. */
|
||
@@ -904,11 +979,11 @@ spu_frame_unwind_cache (struct frame_inf
|
||
{
|
||
/* 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);
|
||
}
|
||
}
|
||
|
||
@@ -917,7 +992,8 @@ spu_frame_unwind_cache (struct frame_inf
|
||
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. */
|
||
@@ -995,24 +1071,28 @@ static const struct frame_base spu_frame
|
||
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
|
||
@@ -1022,9 +1102,111 @@ spu_write_pc (struct regcache *regcache,
|
||
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));
|
||
+}
|
||
+
|
||
+
|
||
+/* Cell/B.E. cross-architecture unwinder support. */
|
||
+
|
||
+struct spu2ppu_cache
|
||
+{
|
||
+ struct frame_id frame_id;
|
||
+ struct regcache *regcache;
|
||
+};
|
||
+
|
||
+static struct gdbarch *
|
||
+spu2ppu_prev_arch (struct frame_info *this_frame, void **this_cache)
|
||
+{
|
||
+ struct spu2ppu_cache *cache = *this_cache;
|
||
+ return get_regcache_arch (cache->regcache);
|
||
+}
|
||
+
|
||
+static void
|
||
+spu2ppu_this_id (struct frame_info *this_frame,
|
||
+ void **this_cache, struct frame_id *this_id)
|
||
+{
|
||
+ struct spu2ppu_cache *cache = *this_cache;
|
||
+ *this_id = cache->frame_id;
|
||
}
|
||
|
||
+static struct value *
|
||
+spu2ppu_prev_register (struct frame_info *this_frame,
|
||
+ void **this_cache, int regnum)
|
||
+{
|
||
+ struct spu2ppu_cache *cache = *this_cache;
|
||
+ struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
|
||
+ gdb_byte *buf;
|
||
+
|
||
+ buf = alloca (register_size (gdbarch, regnum));
|
||
+ regcache_cooked_read (cache->regcache, regnum, buf);
|
||
+ return frame_unwind_got_bytes (this_frame, regnum, buf);
|
||
+}
|
||
+
|
||
+static int
|
||
+spu2ppu_sniffer (const struct frame_unwind *self,
|
||
+ struct frame_info *this_frame, void **this_prologue_cache)
|
||
+{
|
||
+ CORE_ADDR base, func, backchain;
|
||
+ gdb_byte buf[4];
|
||
+
|
||
+ if (gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_spu)
|
||
+ return 0;
|
||
+
|
||
+ base = get_frame_sp (this_frame);
|
||
+ func = get_frame_pc (this_frame);
|
||
+ if (target_read_memory (base, buf, 4))
|
||
+ return 0;
|
||
+ backchain = extract_unsigned_integer (buf, 4);
|
||
+
|
||
+ if (!backchain)
|
||
+ {
|
||
+ struct frame_info *fi;
|
||
+
|
||
+ struct spu2ppu_cache *cache
|
||
+ = FRAME_OBSTACK_CALLOC (1, struct spu2ppu_cache);
|
||
+
|
||
+ cache->frame_id = frame_id_build (base + 16, func);
|
||
+
|
||
+ for (fi = get_next_frame (this_frame); fi; fi = get_next_frame (fi))
|
||
+ if (gdbarch_bfd_arch_info (get_frame_arch (fi))->arch != bfd_arch_spu)
|
||
+ break;
|
||
+
|
||
+ if (fi)
|
||
+ {
|
||
+ cache->regcache = frame_save_as_regcache (fi);
|
||
+ *this_prologue_cache = cache;
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ struct regcache *regcache;
|
||
+ regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
+ cache->regcache = regcache_dup (regcache);
|
||
+ *this_prologue_cache = cache;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+spu2ppu_dealloc_cache (struct frame_info *self, void *this_cache)
|
||
+{
|
||
+ struct spu2ppu_cache *cache = this_cache;
|
||
+ regcache_xfree (cache->regcache);
|
||
+}
|
||
+
|
||
+static const struct frame_unwind spu2ppu_unwind = {
|
||
+ ARCH_FRAME,
|
||
+ spu2ppu_this_id,
|
||
+ spu2ppu_prev_register,
|
||
+ NULL,
|
||
+ spu2ppu_sniffer,
|
||
+ spu2ppu_dealloc_cache,
|
||
+ spu2ppu_prev_arch,
|
||
+};
|
||
+
|
||
|
||
/* Function calling convention. */
|
||
|
||
@@ -1133,7 +1315,7 @@ spu_push_dummy_call (struct gdbarch *gdb
|
||
|
||
/* Set the return address. */
|
||
memset (buf, 0, sizeof buf);
|
||
- store_unsigned_integer (buf, 4, bp_addr);
|
||
+ store_unsigned_integer (buf, 4, SPUADDR_ADDR (bp_addr));
|
||
regcache_cooked_write (regcache, SPU_LR_REGNUM, buf);
|
||
|
||
/* If STRUCT_RETURN is true, then the struct return address (in
|
||
@@ -1142,7 +1324,7 @@ spu_push_dummy_call (struct gdbarch *gdb
|
||
if (struct_return)
|
||
{
|
||
memset (buf, 0, sizeof buf);
|
||
- store_unsigned_integer (buf, 4, struct_addr);
|
||
+ store_unsigned_integer (buf, 4, SPUADDR_ADDR (struct_addr));
|
||
regcache_cooked_write (regcache, regnum++, buf);
|
||
}
|
||
|
||
@@ -1220,9 +1402,10 @@ spu_push_dummy_call (struct gdbarch *gdb
|
||
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. */
|
||
@@ -1302,18 +1485,18 @@ spu_software_single_step (struct frame_i
|
||
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 (next_pc);
|
||
+ insert_single_step_breakpoint (SPUADDR (SPUADDR_SPU (pc), next_pc));
|
||
|
||
if (is_branch (insn, &offset, ®))
|
||
{
|
||
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);
|
||
@@ -1322,12 +1505,35 @@ spu_software_single_step (struct frame_i
|
||
|
||
target = target & (SPU_LS_SIZE - 1);
|
||
if (target != next_pc)
|
||
- insert_single_step_breakpoint (target);
|
||
+ insert_single_step_breakpoint (SPUADDR (SPUADDR_SPU (pc), target));
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
+
|
||
+/* Disassembler. */
|
||
+
|
||
+static void
|
||
+spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
|
||
+{
|
||
+ int id = *(int *)info->application_data;
|
||
+ CORE_ADDR spu_addr = SPUADDR (id, addr);
|
||
+ print_address (spu_addr, info->stream);
|
||
+}
|
||
+
|
||
+static int
|
||
+gdb_print_insn_spu (bfd_vma memaddr, 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. */
|
||
+ int id = SPUADDR_SPU (memaddr);
|
||
+ info->application_data = &id;
|
||
+ info->print_address_func = spu_dis_asm_print_address;
|
||
+ return print_insn_spu (memaddr, info);
|
||
+}
|
||
+
|
||
+
|
||
/* Target overlays for the SPU overlay manager.
|
||
|
||
See the documentation of simple_overlay_update for how the
|
||
@@ -1444,7 +1650,7 @@ static void
|
||
spu_overlay_update_osect (struct obj_section *osect)
|
||
{
|
||
struct spu_overlay_table *ovly_table;
|
||
- CORE_ADDR val;
|
||
+ CORE_ADDR id, val;
|
||
|
||
ovly_table = spu_get_overlay_table (osect->objfile);
|
||
if (!ovly_table)
|
||
@@ -1454,7 +1660,8 @@ spu_overlay_update_osect (struct obj_sec
|
||
if (ovly_table->mapped_ptr == 0)
|
||
return;
|
||
|
||
- val = read_memory_unsigned_integer (ovly_table->mapped_ptr, 4);
|
||
+ id = SPUADDR_SPU (obj_section_addr (osect));
|
||
+ val = read_memory_unsigned_integer (SPUADDR (id, ovly_table->mapped_ptr), 4);
|
||
osect->ovly_mapped = (val == ovly_table->mapped_val);
|
||
}
|
||
|
||
@@ -1516,6 +1723,131 @@ spu_overlay_new_objfile (struct objfile
|
||
}
|
||
|
||
|
||
+/* Insert temporary breakpoint on "main" function of newly loaded
|
||
+ SPE context OBJFILE. */
|
||
+static void
|
||
+spu_catch_start (struct objfile *objfile)
|
||
+{
|
||
+ struct minimal_symbol *minsym;
|
||
+ struct symtab *symtab;
|
||
+ CORE_ADDR pc;
|
||
+ char buf[32];
|
||
+
|
||
+ /* Do this only if requested by "set spu stop-on-load on". */
|
||
+ if (!spu_stop_on_load_p)
|
||
+ return;
|
||
+
|
||
+ /* Consider only SPU objfiles. */
|
||
+ if (!objfile || bfd_get_arch (objfile->obfd) != bfd_arch_spu)
|
||
+ return;
|
||
+
|
||
+ /* The main objfile is handled differently. */
|
||
+ if (objfile == symfile_objfile)
|
||
+ return;
|
||
+
|
||
+ /* There can be multiple symbols named "main". Search for the
|
||
+ "main" in *this* objfile. */
|
||
+ minsym = lookup_minimal_symbol ("main", NULL, objfile);
|
||
+ if (!minsym)
|
||
+ return;
|
||
+
|
||
+ /* If we have debugging information, try to use it -- this
|
||
+ will allow us to properly skip the prologue. */
|
||
+ pc = SYMBOL_VALUE_ADDRESS (minsym);
|
||
+ symtab = find_pc_sect_symtab (pc, SYMBOL_OBJ_SECTION (minsym));
|
||
+ if (symtab != NULL)
|
||
+ {
|
||
+ struct blockvector *bv = BLOCKVECTOR (symtab);
|
||
+ struct block *block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
|
||
+ struct symbol *sym;
|
||
+ struct symtab_and_line sal;
|
||
+
|
||
+ sym = lookup_block_symbol (block, "main", NULL, VAR_DOMAIN);
|
||
+ if (sym)
|
||
+ {
|
||
+ fixup_symbol_section (sym, objfile);
|
||
+ sal = find_function_start_sal (sym, 1);
|
||
+ pc = sal.pc;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Use a numerical address for the tbreak command to avoid having
|
||
+ the breakpoint re-set incorrectly. */
|
||
+ xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
|
||
+ tbreak_command (buf, 0);
|
||
+}
|
||
+
|
||
+/* Lookup OBJFILE corresponding to the current SPU context. */
|
||
+static struct objfile *
|
||
+spu_objfile_from_context (void)
|
||
+{
|
||
+ struct frame_info *frame = get_current_frame ();
|
||
+ struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
+ struct objfile *obj;
|
||
+
|
||
+ if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu)
|
||
+ return NULL;
|
||
+
|
||
+ ALL_OBJFILES (obj)
|
||
+ {
|
||
+ if (obj->sections != obj->sections_end
|
||
+ && SPUADDR_SPU (obj_section_addr (obj->sections)) == tdep->id)
|
||
+ return obj;
|
||
+ }
|
||
+
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+/* Flush cache for ea pointer access if available and return 1. Return 0 if
|
||
+ inferior call was not executed. */
|
||
+static void
|
||
+flush_ea_cache (void)
|
||
+{
|
||
+ struct value *ea_flush_fn = NULL;
|
||
+ struct minimal_symbol *msymbol;
|
||
+ struct objfile *obj;
|
||
+
|
||
+ obj = spu_objfile_from_context ();
|
||
+ if (obj == NULL)
|
||
+ return;
|
||
+
|
||
+ /* Lookup inferior function __cache_flush. */
|
||
+ msymbol = lookup_minimal_symbol ("__cache_flush", NULL, obj);
|
||
+ if (msymbol != NULL)
|
||
+ {
|
||
+ struct type *type;
|
||
+ CORE_ADDR addr;
|
||
+
|
||
+ type = builtin_type_void;
|
||
+ type = lookup_function_type (type);
|
||
+ type = lookup_pointer_type (type);
|
||
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||
+ ea_flush_fn = value_from_pointer (type, addr);
|
||
+ }
|
||
+
|
||
+ if (ea_flush_fn)
|
||
+ call_function_by_hand (ea_flush_fn, 0, NULL);
|
||
+}
|
||
+
|
||
+/* This handler is called when the inferior has stopped. If it is stopped in
|
||
+ SPU architecture then flush the ea cache if used. */
|
||
+static void
|
||
+spu_attach_normal_stop (struct bpstats *bs, int unused)
|
||
+{
|
||
+ if (!spu_auto_flush_cache_p)
|
||
+ return;
|
||
+
|
||
+ if (!target_has_registers || !target_has_stack || !target_has_memory)
|
||
+ return;
|
||
+
|
||
+ /* Temporarily reset the spu_auto_flush_cache_p to avoid recursively
|
||
+ re-entering this function when __cache_flush stops. */
|
||
+ spu_auto_flush_cache_p = 0;
|
||
+ flush_ea_cache ();
|
||
+ spu_auto_flush_cache_p = 1;
|
||
+}
|
||
+
|
||
/* "info spu" commands. */
|
||
|
||
static void
|
||
@@ -2065,6 +2397,37 @@ info_spu_command (char *args, int from_t
|
||
}
|
||
|
||
|
||
+/* Root of all "set spu "/"show spu " commands. */
|
||
+
|
||
+static void
|
||
+show_spu_command (char *args, int from_tty)
|
||
+{
|
||
+ help_list (showspucmdlist, "show spu ", all_commands, gdb_stdout);
|
||
+}
|
||
+
|
||
+static void
|
||
+set_spu_command (char *args, int from_tty)
|
||
+{
|
||
+ help_list (setspucmdlist, "set spu ", all_commands, gdb_stdout);
|
||
+}
|
||
+
|
||
+static void
|
||
+show_spu_stop_on_load (struct ui_file *file, int from_tty,
|
||
+ struct cmd_list_element *c, const char *value)
|
||
+{
|
||
+ fprintf_filtered (file, _("Stopping for new SPE threads is %s.\n"),
|
||
+ value);
|
||
+}
|
||
+
|
||
+static void
|
||
+show_spu_auto_flush_cache (struct ui_file *file, int from_tty,
|
||
+ struct cmd_list_element *c, const char *value)
|
||
+{
|
||
+ fprintf_filtered (file, _("Automatic software-cache flush is %s.\n"),
|
||
+ value);
|
||
+}
|
||
+
|
||
+
|
||
/* Set up gdbarch struct. */
|
||
|
||
static struct gdbarch *
|
||
@@ -2072,22 +2435,30 @@ spu_gdbarch_init (struct gdbarch_info in
|
||
{
|
||
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;
|
||
|
||
- /* 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;
|
||
+ tdep->lslr = id != -1? spu_lslr (id) : SPU_LS_SIZE - 1;
|
||
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);
|
||
@@ -2118,9 +2489,16 @@ spu_gdbarch_init (struct gdbarch_info in
|
||
set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
|
||
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
|
||
|
||
- /* Address conversion. */
|
||
+ /* Address handling. */
|
||
+ 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);
|
||
+ set_gdbarch_address_class_type_flags (gdbarch, spu_address_class_type_flags);
|
||
+ set_gdbarch_address_class_type_flags_to_name
|
||
+ (gdbarch, spu_address_class_type_flags_to_name);
|
||
+ set_gdbarch_address_class_name_to_type_flags
|
||
+ (gdbarch, spu_address_class_name_to_type_flags);
|
||
+
|
||
|
||
/* Inferior function calls. */
|
||
set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
|
||
@@ -2142,6 +2520,9 @@ spu_gdbarch_init (struct gdbarch_info in
|
||
set_gdbarch_skip_prologue (gdbarch, spu_skip_prologue);
|
||
set_gdbarch_in_function_epilogue_p (gdbarch, spu_in_function_epilogue_p);
|
||
|
||
+ /* Cell/B.E. cross-architecture unwinder support. */
|
||
+ frame_unwind_prepend_unwinder (gdbarch, &spu2ppu_unwind);
|
||
+
|
||
/* Breakpoints. */
|
||
set_gdbarch_decr_pc_after_break (gdbarch, 4);
|
||
set_gdbarch_breakpoint_from_pc (gdbarch, spu_breakpoint_from_pc);
|
||
@@ -2163,6 +2544,50 @@ _initialize_spu_tdep (void)
|
||
observer_attach_new_objfile (spu_overlay_new_objfile);
|
||
spu_overlay_data = register_objfile_data ();
|
||
|
||
+ /* Install spu stop-on-load handler. */
|
||
+ observer_attach_new_objfile (spu_catch_start);
|
||
+
|
||
+ /* Add ourselves to normal_stop event chain. */
|
||
+ observer_attach_normal_stop (spu_attach_normal_stop);
|
||
+
|
||
+ /* Add root prefix command for all "set spu"/"show spu" commands. */
|
||
+ add_prefix_cmd ("spu", no_class, set_spu_command,
|
||
+ _("Various SPU specific commands."),
|
||
+ &setspucmdlist, "set spu ", 0, &setlist);
|
||
+ add_prefix_cmd ("spu", no_class, show_spu_command,
|
||
+ _("Various SPU specific commands."),
|
||
+ &showspucmdlist, "show spu ", 0, &showlist);
|
||
+
|
||
+ /* Toggle whether or not to add a temporary breakpoint at the "main"
|
||
+ function of new SPE contexts. */
|
||
+ add_setshow_boolean_cmd ("stop-on-load", class_support,
|
||
+ &spu_stop_on_load_p, _("\
|
||
+Set whether to stop for new SPE threads."),
|
||
+ _("\
|
||
+Show whether to stop for new SPE threads."),
|
||
+ _("\
|
||
+Use \"on\" to give control to the user when a new SPE thread\n\
|
||
+enters its \"main\" function.\n\
|
||
+Use \"off\" to disable stopping for new SPE threads."),
|
||
+ NULL,
|
||
+ show_spu_stop_on_load,
|
||
+ &setspucmdlist, &showspucmdlist);
|
||
+
|
||
+ /* Toggle whether or not to automatically flush the software-managed
|
||
+ cache whenever SPE execution stops. */
|
||
+ add_setshow_boolean_cmd ("auto-flush-cache", class_support,
|
||
+ &spu_auto_flush_cache_p, _("\
|
||
+Set whether to automatically flush the software-managed cache."),
|
||
+ _("\
|
||
+Show whether to automatically flush the software-managed cache."),
|
||
+ _("\
|
||
+Use \"on\" to automatically flush the software-managed cache\n\
|
||
+whenever SPE execution stops.\n\
|
||
+Use \"off\" to never automatically flush the software-managed cache."),
|
||
+ NULL,
|
||
+ show_spu_auto_flush_cache,
|
||
+ &setspucmdlist, &showspucmdlist);
|
||
+
|
||
/* Add root prefix command for all "info spu" commands. */
|
||
add_prefix_cmd ("spu", class_info, info_spu_command,
|
||
_("Various SPU specific commands."),
|
||
--- gdb/spu-tdep.h
|
||
+++ gdb/spu-tdep.h
|
||
@@ -50,4 +50,17 @@ 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))
|
||
+
|
||
+/* SPU multi-architecture support. */
|
||
+extern void set_spu_solib_ops (struct gdbarch *gdbarch);
|
||
+extern void spu_multiarch_enable (void);
|
||
+extern void spu_multiarch_disable (void);
|
||
+
|
||
#endif
|
||
--- gdb/stack.c
|
||
+++ gdb/stack.c
|
||
@@ -45,6 +45,7 @@
|
||
#include "valprint.h"
|
||
#include "gdbthread.h"
|
||
#include "cp-support.h"
|
||
+#include "arch-utils.h"
|
||
|
||
#include "gdb_assert.h"
|
||
#include <ctype.h>
|
||
@@ -109,6 +110,8 @@ print_stack_frame (struct frame_info *fr
|
||
enum print_what print_what)
|
||
{
|
||
struct print_stack_frame_args args;
|
||
+ struct cleanup *old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (frame);
|
||
|
||
args.frame = frame;
|
||
args.print_level = print_level;
|
||
@@ -118,6 +121,7 @@ print_stack_frame (struct frame_info *fr
|
||
args.print_args = 1;
|
||
|
||
catch_errors (print_stack_frame_stub, &args, "", RETURN_MASK_ERROR);
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
|
||
struct print_args_args
|
||
@@ -223,6 +227,9 @@ print_frame_args (struct symbol *func, s
|
||
stb = ui_out_stream_new (uiout);
|
||
old_chain = make_cleanup_ui_out_stream_delete (stb);
|
||
|
||
+ save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (frame);
|
||
+
|
||
if (func)
|
||
{
|
||
struct block *b = SYMBOL_BLOCK_VALUE (func);
|
||
@@ -474,9 +481,11 @@ print_frame_info (struct frame_info *fra
|
||
struct symtab_and_line sal;
|
||
int source_print;
|
||
int location_print;
|
||
+ struct cleanup *old_chain;
|
||
|
||
if (get_frame_type (frame) == DUMMY_FRAME
|
||
- || get_frame_type (frame) == SIGTRAMP_FRAME)
|
||
+ || get_frame_type (frame) == SIGTRAMP_FRAME
|
||
+ || get_frame_type (frame) == ARCH_FRAME)
|
||
{
|
||
struct cleanup *uiout_cleanup
|
||
= make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
|
||
@@ -509,6 +518,10 @@ print_frame_info (struct frame_info *fra
|
||
annotate_signal_handler_caller ();
|
||
ui_out_field_string (uiout, "func", "<signal handler called>");
|
||
}
|
||
+ else if (get_frame_type (frame) == ARCH_FRAME)
|
||
+ {
|
||
+ ui_out_field_string (uiout, "func", "<cross-architecture call>");
|
||
+ }
|
||
ui_out_text (uiout, "\n");
|
||
annotate_frame_end ();
|
||
|
||
@@ -522,6 +535,10 @@ print_frame_info (struct frame_info *fra
|
||
the next frame is a SIGTRAMP_FRAME or a DUMMY_FRAME, then the
|
||
next frame was not entered as the result of a call, and we want
|
||
to get the line containing FRAME->pc. */
|
||
+
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (frame);
|
||
+
|
||
find_frame_sal (frame, &sal);
|
||
|
||
location_print = (print_what == LOCATION
|
||
@@ -577,6 +594,7 @@ print_frame_info (struct frame_info *fra
|
||
annotate_frame_end ();
|
||
|
||
gdb_flush (gdb_stdout);
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
|
||
static void
|
||
@@ -1435,6 +1453,7 @@ static void
|
||
print_frame_local_vars (struct frame_info *frame, int num_tabs,
|
||
struct ui_file *stream)
|
||
{
|
||
+ struct cleanup *old_chain;
|
||
struct block *block = get_frame_block (frame, 0);
|
||
int values_printed = 0;
|
||
|
||
@@ -1444,6 +1463,9 @@ print_frame_local_vars (struct frame_inf
|
||
return;
|
||
}
|
||
|
||
+ old_chain = save_current_gdbarch ();
|
||
+ current_gdbarch = get_frame_arch (frame);
|
||
+
|
||
while (block)
|
||
{
|
||
if (print_block_frame_locals (block, frame, num_tabs, stream))
|
||
@@ -1457,6 +1479,8 @@ print_frame_local_vars (struct frame_inf
|
||
|
||
if (!values_printed)
|
||
fprintf_filtered (stream, _("No locals.\n"));
|
||
+
|
||
+ do_cleanups (old_chain);
|
||
}
|
||
|
||
/* Same, but print labels. */
|
||
--- gdb/target-descriptions.c
|
||
+++ gdb/target-descriptions.c
|
||
@@ -104,6 +104,10 @@ typedef struct tdesc_feature
|
||
} *tdesc_feature_p;
|
||
DEF_VEC_P(tdesc_feature_p);
|
||
|
||
+/* A compatible architecture from a target description. */
|
||
+typedef const struct bfd_arch_info *arch_p;
|
||
+DEF_VEC_P(arch_p);
|
||
+
|
||
/* A target description. */
|
||
|
||
struct target_desc
|
||
@@ -111,6 +115,9 @@ struct target_desc
|
||
/* The architecture reported by the target, if any. */
|
||
const struct bfd_arch_info *arch;
|
||
|
||
+ /* The list of compatible architectures reported by the target. */
|
||
+ VEC(arch_p) *compatible;
|
||
+
|
||
/* Any architecture-specific properties specified by the target. */
|
||
VEC(property_s) *properties;
|
||
|
||
@@ -290,6 +297,28 @@ tdesc_architecture (const struct target_
|
||
{
|
||
return target_desc->arch;
|
||
}
|
||
+
|
||
+/* Return non-zero if this target description is compatible
|
||
+ with the given BFD architecture. */
|
||
+
|
||
+int
|
||
+tdesc_compatible_p (const struct target_desc *target_desc,
|
||
+ const struct bfd_arch_info *arch)
|
||
+{
|
||
+ const struct bfd_arch_info *compat;
|
||
+ int ix;
|
||
+
|
||
+ for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat);
|
||
+ ix++)
|
||
+ {
|
||
+ if (compat == arch
|
||
+ || arch->compatible (arch, compat)
|
||
+ || compat->compatible (compat, arch))
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
|
||
|
||
/* Return 1 if this target description includes any registers. */
|
||
@@ -885,6 +914,8 @@ free_target_description (void *arg)
|
||
}
|
||
VEC_free (property_s, target_desc->properties);
|
||
|
||
+ VEC_free (arch_p, target_desc->compatible);
|
||
+
|
||
xfree (target_desc);
|
||
}
|
||
|
||
@@ -895,6 +926,30 @@ make_cleanup_free_target_description (st
|
||
}
|
||
|
||
void
|
||
+tdesc_add_compatible (struct target_desc *target_desc,
|
||
+ const struct bfd_arch_info *compatible)
|
||
+{
|
||
+ const struct bfd_arch_info *compat;
|
||
+ int ix;
|
||
+
|
||
+ /* If this instance of GDB is compiled without BFD support for the
|
||
+ compatible architecture, simply ignore it -- we would not be able
|
||
+ to handle it anyway. */
|
||
+ if (compatible == NULL)
|
||
+ return;
|
||
+
|
||
+ for (ix = 0; VEC_iterate (arch_p, target_desc->compatible, ix, compat);
|
||
+ ix++)
|
||
+ if (compat == compatible)
|
||
+ internal_error (__FILE__, __LINE__,
|
||
+ _("Attempted to add duplicate "
|
||
+ "compatible architecture \"%s\""),
|
||
+ compatible->printable_name);
|
||
+
|
||
+ VEC_safe_push (arch_p, target_desc->compatible, compatible);
|
||
+}
|
||
+
|
||
+void
|
||
set_tdesc_property (struct target_desc *target_desc,
|
||
const char *key, const char *value)
|
||
{
|
||
@@ -993,6 +1048,7 @@ static void
|
||
maint_print_c_tdesc_cmd (char *args, int from_tty)
|
||
{
|
||
const struct target_desc *tdesc;
|
||
+ const struct bfd_arch_info *compatible;
|
||
const char *filename, *inp;
|
||
char *function, *outp;
|
||
struct property *prop;
|
||
@@ -1049,6 +1105,16 @@ maint_print_c_tdesc_cmd (char *args, int
|
||
printf_unfiltered ("\n");
|
||
}
|
||
|
||
+ for (ix = 0; VEC_iterate (arch_p, tdesc->compatible, ix, compatible);
|
||
+ ix++)
|
||
+ {
|
||
+ printf_unfiltered
|
||
+ (" tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n",
|
||
+ compatible->printable_name);
|
||
+ }
|
||
+ if (ix)
|
||
+ printf_unfiltered ("\n");
|
||
+
|
||
for (ix = 0; VEC_iterate (property_s, tdesc->properties, ix, prop);
|
||
ix++)
|
||
{
|
||
--- gdb/target-descriptions.h
|
||
+++ gdb/target-descriptions.h
|
||
@@ -123,6 +123,12 @@ int tdesc_numbered_register_choices (con
|
||
const struct bfd_arch_info *tdesc_architecture
|
||
(const struct target_desc *);
|
||
|
||
+/* Return non-zero if this target description is compatible
|
||
+ with the given BFD architecture. */
|
||
+
|
||
+int tdesc_compatible_p (const struct target_desc *,
|
||
+ const struct bfd_arch_info *);
|
||
+
|
||
/* Return the string value of a property named KEY, or NULL if the
|
||
property was not specified. */
|
||
|
||
@@ -169,6 +175,8 @@ void set_tdesc_architecture (struct targ
|
||
const struct bfd_arch_info *);
|
||
void set_tdesc_property (struct target_desc *,
|
||
const char *key, const char *value);
|
||
+void tdesc_add_compatible (struct target_desc *,
|
||
+ const struct bfd_arch_info *);
|
||
|
||
struct tdesc_feature *tdesc_create_feature (struct target_desc *tdesc,
|
||
const char *name);
|
||
--- gdb/target.c
|
||
+++ gdb/target.c
|
||
@@ -91,6 +91,9 @@ static LONGEST target_xfer_partial (stru
|
||
void *readbuf, const void *writebuf,
|
||
ULONGEST offset, LONGEST len);
|
||
|
||
+static struct gdbarch *default_thread_architecture (struct target_ops *ops,
|
||
+ ptid_t ptid);
|
||
+
|
||
static void init_dummy_target (void);
|
||
|
||
static struct target_ops debug_target;
|
||
@@ -480,6 +483,7 @@ update_current_target (void)
|
||
INHERIT (to_find_memory_regions, t);
|
||
INHERIT (to_make_corefile_notes, t);
|
||
/* Do not inherit to_get_thread_local_address. */
|
||
+ INHERIT (to_thread_architecture, t);
|
||
INHERIT (to_can_execute_reverse, t);
|
||
/* Do not inherit to_read_description. */
|
||
INHERIT (to_get_ada_task_ptid, t);
|
||
@@ -639,6 +643,8 @@ update_current_target (void)
|
||
de_fault (to_async_mask,
|
||
(int (*) (int))
|
||
return_one);
|
||
+ de_fault (to_thread_architecture,
|
||
+ default_thread_architecture);
|
||
current_target.to_read_description = NULL;
|
||
de_fault (to_get_ada_task_ptid,
|
||
(ptid_t (*) (long, long))
|
||
@@ -2134,7 +2140,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 (_("\
|
||
@@ -2294,6 +2301,12 @@ default_watchpoint_addr_within_range (st
|
||
return addr >= start && addr < start + length;
|
||
}
|
||
|
||
+static struct gdbarch *
|
||
+default_thread_architecture (struct target_ops *ops, ptid_t ptid)
|
||
+{
|
||
+ return target_gdbarch;
|
||
+}
|
||
+
|
||
static int
|
||
return_zero (void)
|
||
{
|
||
@@ -3145,6 +3158,19 @@ debug_to_find_new_threads (void)
|
||
fputs_unfiltered ("target_find_new_threads ()\n", gdb_stdlog);
|
||
}
|
||
|
||
+static struct gdbarch *
|
||
+debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
|
||
+{
|
||
+ struct gdbarch *retval;
|
||
+
|
||
+ retval = debug_target.to_thread_architecture (ops, ptid);
|
||
+
|
||
+ fprintf_unfiltered (gdb_stdlog, "target_thread_architecture (%s) = %p [%s]\n",
|
||
+ target_pid_to_str (ptid), retval,
|
||
+ gdbarch_bfd_arch_info (retval)->printable_name);
|
||
+ return retval;
|
||
+}
|
||
+
|
||
static void
|
||
debug_to_stop (ptid_t ptid)
|
||
{
|
||
@@ -3224,6 +3250,7 @@ setup_target_debug (void)
|
||
current_target.to_stop = debug_to_stop;
|
||
current_target.to_rcmd = debug_to_rcmd;
|
||
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
|
||
+ current_target.to_thread_architecture = debug_to_thread_architecture;
|
||
}
|
||
|
||
|
||
--- gdb/target.h
|
||
+++ gdb/target.h
|
||
@@ -62,7 +62,8 @@ enum strata
|
||
file_stratum, /* Executable files, etc */
|
||
core_stratum, /* Core dump files */
|
||
process_stratum, /* Executing processes */
|
||
- thread_stratum /* Executing threads */
|
||
+ thread_stratum, /* Executing threads */
|
||
+ arch_stratum /* Architecture overrides */
|
||
};
|
||
|
||
enum thread_control_capabilities
|
||
@@ -544,6 +545,9 @@ struct target_ops
|
||
simultaneously? */
|
||
int (*to_supports_multi_process) (void);
|
||
|
||
+ /* Determine current architecture of thread PTID. */
|
||
+ struct gdbarch *(*to_thread_architecture) (struct target_ops *, ptid_t);
|
||
+
|
||
int to_magic;
|
||
/* Need sub-structure for target machine related rather than comm related?
|
||
*/
|
||
@@ -1043,6 +1047,11 @@ extern char *normal_pid_to_str (ptid_t p
|
||
#define target_pid_to_exec_file(pid) \
|
||
(current_target.to_pid_to_exec_file) (pid)
|
||
|
||
+/* Determine current architecture of thread PTID. */
|
||
+
|
||
+#define target_thread_architecture(ptid) \
|
||
+ (current_target.to_thread_architecture (¤t_target, ptid))
|
||
+
|
||
/*
|
||
* Iterator function for target memory regions.
|
||
* Calls a callback function once for each memory region 'mapped'
|
||
--- gdb/testsuite/gdb.base/dump.exp
|
||
+++ gdb/testsuite/gdb.base/dump.exp
|
||
@@ -42,6 +42,12 @@ if {[istarget "ia64*-*-*"] || [istarget
|
||
set is64bitonly "yes"
|
||
}
|
||
|
||
+if {[istarget "spu*-*-*"]} then {
|
||
+ # The internal address format used for the combined Cell/B.E.
|
||
+ # debugger required 64-bit.
|
||
+ set is64bitonly "yes"
|
||
+}
|
||
+
|
||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ${options}] != "" } {
|
||
untested dump.exp
|
||
return -1
|
||
--- gdb/testsuite/gdb.xml/tdesc-regs.exp
|
||
+++ gdb/testsuite/gdb.xml/tdesc-regs.exp
|
||
@@ -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
|
||
--- gdb/thread.c
|
||
+++ gdb/thread.c
|
||
@@ -824,6 +824,7 @@ switch_to_thread (ptid_t ptid)
|
||
inferior_ptid = ptid;
|
||
reinit_frame_cache ();
|
||
registers_changed ();
|
||
+ current_gdbarch = get_regcache_arch (get_current_regcache ());
|
||
|
||
/* We don't check for is_stopped, because we're called at times
|
||
while in the TARGET_RUNNING state, e.g., while handling an
|
||
--- gdb/utils.c
|
||
+++ gdb/utils.c
|
||
@@ -3119,7 +3119,6 @@ core_addr_to_string_nz (const CORE_ADDR
|
||
CORE_ADDR
|
||
string_to_core_addr (const char *my_string)
|
||
{
|
||
- int addr_bit = gdbarch_addr_bit (current_gdbarch);
|
||
CORE_ADDR addr = 0;
|
||
|
||
if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
|
||
@@ -3135,17 +3134,6 @@ string_to_core_addr (const char *my_stri
|
||
else
|
||
error (_("invalid hex \"%s\""), my_string);
|
||
}
|
||
-
|
||
- /* Not very modular, but if the executable format expects
|
||
- addresses to be sign-extended, then do so if the address was
|
||
- specified with only 32 significant bits. Really this should
|
||
- be determined by the target architecture, not by the object
|
||
- file. */
|
||
- if (i - 2 == addr_bit / 4
|
||
- && exec_bfd
|
||
- && bfd_get_sign_extend_vma (exec_bfd))
|
||
- addr = (addr ^ ((CORE_ADDR) 1 << (addr_bit - 1)))
|
||
- - ((CORE_ADDR) 1 << (addr_bit - 1));
|
||
}
|
||
else
|
||
{
|
||
--- gdb/varobj.c
|
||
+++ gdb/varobj.c
|
||
@@ -427,6 +427,8 @@ static struct frame_info *
|
||
find_frame_addr_in_frame_chain (CORE_ADDR frame_addr)
|
||
{
|
||
struct frame_info *frame = NULL;
|
||
+ CORE_ADDR frame_base;
|
||
+ int addr_bit;
|
||
|
||
if (frame_addr == (CORE_ADDR) 0)
|
||
return NULL;
|
||
@@ -435,7 +437,16 @@ find_frame_addr_in_frame_chain (CORE_ADD
|
||
frame != NULL;
|
||
frame = get_prev_frame (frame))
|
||
{
|
||
- if (get_frame_base_address (frame) == frame_addr)
|
||
+ /* The CORE_ADDR we get as argument was parsed from a string GDB
|
||
+ output as $fp. This output got truncated to gdbarch_addr_bit.
|
||
+ Truncate the frame base address in the same manner before
|
||
+ comparing it against our argument. */
|
||
+ frame_base = get_frame_base_address (frame);
|
||
+ addr_bit = gdbarch_addr_bit (get_frame_arch (frame));
|
||
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
|
||
+ frame_base &= ((CORE_ADDR) 1 << addr_bit) - 1;
|
||
+
|
||
+ if (frame_base == frame_addr)
|
||
return frame;
|
||
}
|
||
|
||
--- gdb/xml-tdesc.c
|
||
+++ gdb/xml-tdesc.c
|
||
@@ -106,6 +106,20 @@ tdesc_end_arch (struct gdb_xml_parser *p
|
||
set_tdesc_architecture (data->tdesc, arch);
|
||
}
|
||
|
||
+/* Handle the end of a <compatible> element and its value. */
|
||
+
|
||
+static void
|
||
+tdesc_end_compatible (struct gdb_xml_parser *parser,
|
||
+ const struct gdb_xml_element *element,
|
||
+ void *user_data, const char *body_text)
|
||
+{
|
||
+ struct tdesc_parsing_data *data = user_data;
|
||
+ const struct bfd_arch_info *arch;
|
||
+
|
||
+ arch = bfd_scan_arch (body_text);
|
||
+ tdesc_add_compatible (data->tdesc, arch);
|
||
+}
|
||
+
|
||
/* Handle the start of a <target> element. */
|
||
|
||
static void
|
||
@@ -345,6 +359,8 @@ static const struct gdb_xml_attribute ta
|
||
static const struct gdb_xml_element target_children[] = {
|
||
{ "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
|
||
NULL, tdesc_end_arch },
|
||
+ { "compatible", NULL, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||
+ NULL, tdesc_end_compatible },
|
||
{ "feature", feature_attributes, feature_children,
|
||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||
tdesc_start_feature, NULL },
|
||
--- gdb/xstormy16-tdep.c
|
||
+++ gdb/xstormy16-tdep.c
|
||
@@ -592,7 +592,8 @@ xstormy16_skip_trampoline_code (struct f
|
||
and vice versa. */
|
||
|
||
static CORE_ADDR
|
||
-xstormy16_pointer_to_address (struct type *type, const gdb_byte *buf)
|
||
+xstormy16_pointer_to_address (struct gdbarch *gdbarch,
|
||
+ struct type *type, const gdb_byte *buf)
|
||
{
|
||
enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
|
||
CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
|
||
@@ -608,7 +609,8 @@ xstormy16_pointer_to_address (struct typ
|
||
}
|
||
|
||
static void
|
||
-xstormy16_address_to_pointer (struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
+xstormy16_address_to_pointer (struct gdbarch *gdbarch,
|
||
+ struct type *type, gdb_byte *buf, CORE_ADDR addr)
|
||
{
|
||
enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
|
||
|