mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
* ppc-linux-tdep.c: Include "solib.h", "solist.h", "exceptions.h",
"arch-utils.h", and "spu-tdep.h". (spu_context_objfile, spe_context_lm_addr, spe_context_offset): New static variables. (spe_context_cache_ptid, spe_context_cache_address): Likewise. (ppc_linux_spe_context_lookup): New function. (ppc_linux_spe_context_inferior_created): Likewise. (ppc_linux_spe_context_solib_loaded): Likewise. (ppc_linux_spe_context_solib_unloaded): Likewise. (ppc_linux_spe_context): Likewise. (struct ppu2spu_cache, struct ppu2spu_data): New data types. (ppu2spu_prev_arch, ppu2spu_this_id, ppu2spu_prev_register, ppu2spu_unwind_register, ppu2spu_sniffer, ppu2spu_dealloc_cache): New functions. (ppu2spu_unwind): New static variable. (ppc_linux_init_abi): Install cross-architecture unwinder. (_initialize_ppc_linux_tdep): Attach to observers. * spu-tdep.c (struct spu2ppu_cache): New data type. (spu2ppu_prev_arch, spu2ppu_this_id, spu2ppu_prev_register, spu2ppu_sniffer, spu2ppu_dealloc_cache): New functions. (spu2ppu_unwind): New static variable. (spu_gdbarch_init): Install cross-architecture unwinder.
This commit is contained in:
parent
0b9ff2c0a4
commit
cc5f0d6150
@ -1,3 +1,29 @@
|
||||
2009-07-31 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* ppc-linux-tdep.c: Include "solib.h", "solist.h", "exceptions.h",
|
||||
"arch-utils.h", and "spu-tdep.h".
|
||||
(spu_context_objfile, spe_context_lm_addr, spe_context_offset):
|
||||
New static variables.
|
||||
(spe_context_cache_ptid, spe_context_cache_address): Likewise.
|
||||
(ppc_linux_spe_context_lookup): New function.
|
||||
(ppc_linux_spe_context_inferior_created): Likewise.
|
||||
(ppc_linux_spe_context_solib_loaded): Likewise.
|
||||
(ppc_linux_spe_context_solib_unloaded): Likewise.
|
||||
(ppc_linux_spe_context): Likewise.
|
||||
(struct ppu2spu_cache, struct ppu2spu_data): New data types.
|
||||
(ppu2spu_prev_arch, ppu2spu_this_id, ppu2spu_prev_register,
|
||||
ppu2spu_unwind_register, ppu2spu_sniffer,
|
||||
ppu2spu_dealloc_cache): New functions.
|
||||
(ppu2spu_unwind): New static variable.
|
||||
(ppc_linux_init_abi): Install cross-architecture unwinder.
|
||||
(_initialize_ppc_linux_tdep): Attach to observers.
|
||||
|
||||
* spu-tdep.c (struct spu2ppu_cache): New data type.
|
||||
(spu2ppu_prev_arch, spu2ppu_this_id, spu2ppu_prev_register,
|
||||
spu2ppu_sniffer, spu2ppu_dealloc_cache): New functions.
|
||||
(spu2ppu_unwind): New static variable.
|
||||
(spu_gdbarch_init): Install cross-architecture unwinder.
|
||||
|
||||
2009-07-31 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* target.h (enum strata): New value arch_stratum.
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "regset.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "solib-spu.h"
|
||||
#include "solib.h"
|
||||
#include "solist.h"
|
||||
#include "ppc-tdep.h"
|
||||
#include "ppc-linux-tdep.h"
|
||||
#include "trad-frame.h"
|
||||
@ -42,6 +44,9 @@
|
||||
#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"
|
||||
@ -1125,6 +1130,293 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Cell/B.E. active SPE context tracking support. */
|
||||
|
||||
static struct objfile *spe_context_objfile = NULL;
|
||||
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;
|
||||
|
||||
/* Hook into inferior_created, solib_loaded, and solib_unloaded observers
|
||||
to track whether we've loaded a version of libspe2 (as static or dynamic
|
||||
library) that provides the __spe_current_active_context variable. */
|
||||
static void
|
||||
ppc_linux_spe_context_lookup (struct objfile *objfile)
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
|
||||
if (!objfile)
|
||||
{
|
||||
spe_context_objfile = NULL;
|
||||
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_objfile = objfile;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_linux_spe_context_inferior_created (struct target_ops *t, int from_tty)
|
||||
{
|
||||
struct objfile *objfile;
|
||||
|
||||
ppc_linux_spe_context_lookup (NULL);
|
||||
ALL_OBJFILES (objfile)
|
||||
ppc_linux_spe_context_lookup (objfile);
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_linux_spe_context_solib_loaded (struct so_list *so)
|
||||
{
|
||||
if (strstr (so->so_original_name, "/libspe") != NULL)
|
||||
{
|
||||
solib_read_symbols (so, so->from_tty ? SYMFILE_VERBOSE : 0);
|
||||
ppc_linux_spe_context_lookup (so->objfile);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_linux_spe_context_solib_unloaded (struct so_list *so)
|
||||
{
|
||||
if (so->objfile == spe_context_objfile)
|
||||
ppc_linux_spe_context_lookup (NULL);
|
||||
}
|
||||
|
||||
/* 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, enum bfd_endian byte_order,
|
||||
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_objfile)
|
||||
return 0;
|
||||
|
||||
/* Look up cached address of thread-local variable. */
|
||||
if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
|
||||
{
|
||||
struct target_ops *target = ¤t_target;
|
||||
volatile struct gdb_exception ex;
|
||||
|
||||
while (target && !target->to_get_thread_local_address)
|
||||
target = find_target_beneath (target);
|
||||
if (!target)
|
||||
return 0;
|
||||
|
||||
TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||||
{
|
||||
/* We do not call target_translate_tls_address here, because
|
||||
svr4_fetch_objfile_link_map may invalidate the frame chain,
|
||||
which must not do while inside a frame sniffer.
|
||||
|
||||
Instead, we have cached the lm_addr value, and use that to
|
||||
directly call the target's to_get_thread_local_address. */
|
||||
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, byte_order);
|
||||
|
||||
/* 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, byte_order);
|
||||
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, byte_order);
|
||||
if (npc)
|
||||
*npc = extract_unsigned_integer (buf + 4, 4, byte_order);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
struct gdbarch *gdbarch;
|
||||
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;
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (data->gdbarch);
|
||||
|
||||
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, byte_order, data->id);
|
||||
else if (regnum == SPU_PC_REGNUM)
|
||||
store_unsigned_integer (buf, 4, byte_order, 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);
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (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, byte_order);
|
||||
|
||||
spe_context = ppc_linux_spe_context (tdep->wordsize, byte_order,
|
||||
n, &data.id, &data.npc);
|
||||
if (spe_context && base <= spe_context && spe_context < backchain)
|
||||
{
|
||||
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;
|
||||
data.gdbarch = gdbarch_find_by_info (info);
|
||||
if (!data.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 (data.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)
|
||||
@ -1241,6 +1533,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
||||
/* 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,
|
||||
@ -1266,6 +1561,11 @@ _initialize_ppc_linux_tdep (void)
|
||||
/* Attach to inferior_created observer. */
|
||||
observer_attach_inferior_created (ppc_linux_inferior_created);
|
||||
|
||||
/* Attach to observers to track __spe_current_active_context. */
|
||||
observer_attach_inferior_created (ppc_linux_spe_context_inferior_created);
|
||||
observer_attach_solib_loaded (ppc_linux_spe_context_solib_loaded);
|
||||
observer_attach_solib_unloaded (ppc_linux_spe_context_solib_unloaded);
|
||||
|
||||
/* Initialize the Linux target descriptions. */
|
||||
initialize_tdesc_powerpc_32l ();
|
||||
initialize_tdesc_powerpc_altivec32l ();
|
||||
|
107
gdb/spu-tdep.c
107
gdb/spu-tdep.c
@ -1088,6 +1088,110 @@ spu_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
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, byte_order);
|
||||
|
||||
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. */
|
||||
|
||||
static CORE_ADDR
|
||||
@ -2310,6 +2414,9 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user