/* SPU target-dependent code for GDB, the GNU debugger.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
Based on a port by Sid Manning <sid@us.ibm.com>.
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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "arch-utils.h"
append_composite_type_field (t, "v16_int8",
init_vector_type (builtin_type_int8, 16));
append_composite_type_field (t, "v2_double",
- init_vector_type (builtin_type_double, 2));
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_double, 2));
append_composite_type_field (t, "v4_float",
- init_vector_type (builtin_type_float, 4));
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_float, 4));
- TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_VECTOR (t) = 1;
TYPE_NAME (t) = "spu_builtin_type_vec128";
tdep->spu_builtin_type_vec128 = t;
/* Registers. */
static const char *
-spu_register_name (int reg_nr)
+spu_register_name (struct gdbarch *gdbarch, int reg_nr)
{
static char *register_names[] =
{
return builtin_type_uint32;
case SPU_PC_REGNUM:
- return builtin_type_void_func_ptr;
+ return builtin_type (gdbarch)->builtin_func_ptr;
case SPU_SP_REGNUM:
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
case SPU_FPSCR_REGNUM:
return builtin_type_uint128;
return default_register_reggroup_p (gdbarch, regnum, group);
}
+/* Address conversion. */
+
+static CORE_ADDR
+spu_pointer_to_address (struct type *type, const gdb_byte *buf)
+{
+ 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);
+
+ return addr & lslr;
+}
+
+static CORE_ADDR
+spu_integer_to_address (struct gdbarch *gdbarch,
+ struct type *type, const gdb_byte *buf)
+{
+ ULONGEST addr = unpack_long (type, buf);
+ ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */
+
+ if (target_has_registers && target_has_stack && target_has_memory)
+ lslr = get_frame_register_unsigned (get_selected_frame (NULL),
+ SPU_LSLR_REGNUM);
+
+ return addr & lslr;
+}
+
/* Decoding SPU instructions. */
/* Return the first instruction after the prologue starting at PC. */
static CORE_ADDR
-spu_skip_prologue (CORE_ADDR pc)
+spu_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
struct spu_prologue_data data;
return spu_analyze_prologue (pc, (CORE_ADDR)-1, &data);
/* Return the frame pointer in use at address PC. */
static void
-spu_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
+spu_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc,
+ int *reg, LONGEST *offset)
{
struct spu_prologue_data data;
spu_analyze_prologue (pc, (CORE_ADDR)-1, &data);
};
static struct spu_unwind_cache *
-spu_frame_unwind_cache (struct frame_info *next_frame,
+spu_frame_unwind_cache (struct frame_info *this_frame,
void **this_prologue_cache)
{
struct spu_unwind_cache *info;
info = FRAME_OBSTACK_ZALLOC (struct spu_unwind_cache);
*this_prologue_cache = info;
- info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+ info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
info->frame_base = 0;
info->local_base = 0;
/* Find the start of the current function, and analyze its prologue. */
- info->func = frame_func_unwind (next_frame, NORMAL_FRAME);
+ info->func = get_frame_func (this_frame);
if (info->func == 0)
{
/* Fall back to using the current PC as frame ID. */
- info->func = frame_pc_unwind (next_frame);
+ info->func = get_frame_pc (this_frame);
data.size = -1;
}
else
- spu_analyze_prologue (info->func, frame_pc_unwind (next_frame), &data);
+ spu_analyze_prologue (info->func, get_frame_pc (this_frame), &data);
/* If successful, use prologue analysis data. */
int i;
/* Determine CFA via unwound CFA_REG plus CFA_OFFSET. */
- frame_unwind_register (next_frame, data.cfa_reg, buf);
+ get_frame_register (this_frame, data.cfa_reg, buf);
cfa = extract_unsigned_integer (buf, 4) + data.cfa_offset;
/* Call-saved register slots. */
/* Otherwise, fall back to reading the backchain link. */
else
{
- CORE_ADDR reg, backchain;
+ CORE_ADDR reg;
+ LONGEST backchain;
+ int status;
/* Get the backchain. */
- reg = frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
- backchain = read_memory_unsigned_integer (reg, 4);
+ reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
+ status = safe_read_memory_integer (reg, 4, &backchain);
/* A zero backchain terminates the frame chain. Also, sanity
check against the local store size limit. */
- if (backchain != 0 && backchain < SPU_LS_SIZE)
+ if (status && backchain > 0 && backchain < SPU_LS_SIZE)
{
/* Assume the link register is saved into its slot. */
if (backchain + 16 < SPU_LS_SIZE)
}
}
+ /* If we didn't find a frame, we cannot determine SP / return address. */
+ if (info->frame_base == 0)
+ return info;
+
/* The previous SP is equal to the CFA. */
trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, info->frame_base);
if (trad_frame_addr_p (info->saved_regs, SPU_LR_REGNUM))
target_read_memory (info->saved_regs[SPU_LR_REGNUM].addr, buf, 16);
else
- frame_unwind_register (next_frame, SPU_LR_REGNUM, buf);
+ get_frame_register (this_frame, SPU_LR_REGNUM, buf);
/* Normally, the return address is contained in the slot 0 of the
link register, and slots 1-3 are zero. For an overlay return,
}
static void
-spu_frame_this_id (struct frame_info *next_frame,
+spu_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache, struct frame_id *this_id)
{
struct spu_unwind_cache *info =
- spu_frame_unwind_cache (next_frame, this_prologue_cache);
+ spu_frame_unwind_cache (this_frame, this_prologue_cache);
if (info->frame_base == 0)
return;
*this_id = frame_id_build (info->frame_base, info->func);
}
-static void
-spu_frame_prev_register (struct frame_info *next_frame,
- void **this_prologue_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR * addrp,
- int *realnump, gdb_byte *bufferp)
+static struct value *
+spu_frame_prev_register (struct frame_info *this_frame,
+ void **this_prologue_cache, int regnum)
{
struct spu_unwind_cache *info
- = spu_frame_unwind_cache (next_frame, this_prologue_cache);
+ = spu_frame_unwind_cache (this_frame, this_prologue_cache);
/* Special-case the stack pointer. */
if (regnum == SPU_RAW_SP_REGNUM)
regnum = SPU_SP_REGNUM;
- trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
}
static const struct frame_unwind spu_frame_unwind = {
NORMAL_FRAME,
spu_frame_this_id,
- spu_frame_prev_register
+ spu_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-const struct frame_unwind *
-spu_frame_sniffer (struct frame_info *next_frame)
-{
- return &spu_frame_unwind;
-}
-
static CORE_ADDR
-spu_frame_base_address (struct frame_info *next_frame, void **this_cache)
+spu_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct spu_unwind_cache *info
- = spu_frame_unwind_cache (next_frame, this_cache);
+ = spu_frame_unwind_cache (this_frame, this_cache);
return info->local_base;
}
return sp & ~15;
}
+static CORE_ADDR
+spu_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
+ struct value **args, int nargs, struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
+{
+ /* Allocate space sufficient for a breakpoint, keeping the stack aligned. */
+ sp = (sp - 4) & ~15;
+ /* Store the address of that breakpoint */
+ *bp_addr = sp;
+ /* The call starts at the callee's entry point. */
+ *real_pc = funaddr;
+
+ return sp;
+}
+
static int
spu_scalar_value_p (struct type *type)
{
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
+ CORE_ADDR sp_delta;
int i;
int regnum = SPU_ARG1_REGNUM;
int stack_arg = -1;
regcache_cooked_read (regcache, SPU_RAW_SP_REGNUM, buf);
target_write_memory (sp, buf, 16);
- /* Finally, update the SP register. */
- regcache_cooked_write_unsigned (regcache, SPU_SP_REGNUM, sp);
+ /* Finally, update all slots of the SP register. */
+ sp_delta = sp - extract_unsigned_integer (buf, 4);
+ for (i = 0; i < 4; i++)
+ {
+ CORE_ADDR sp_slot = extract_unsigned_integer (buf + 4*i, 4);
+ store_unsigned_integer (buf + 4*i, 4, sp_slot + sp_delta);
+ }
+ regcache_cooked_write (regcache, SPU_RAW_SP_REGNUM, buf);
return sp;
}
static struct frame_id
-spu_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+spu_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
- return frame_id_build (spu_unwind_sp (gdbarch, next_frame),
- spu_unwind_pc (gdbarch, next_frame));
+ 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);
}
/* Function return value access. */
static enum return_value_convention
-spu_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *out, const gdb_byte *in)
+spu_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *out, const gdb_byte *in)
{
enum return_value_convention rvc;
/* Breakpoints. */
static const gdb_byte *
-spu_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
+spu_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
{
static const gdb_byte breakpoint[] = { 0x00, 0x00, 0x3f, 0xff };
struct objfile *objfile;
ALL_OBJSECTIONS (objfile, osect)
- if (section_is_overlay (osect->the_bfd_section))
+ if (section_is_overlay (osect))
spu_overlay_update_osect (osect);
}
}
if (!objfile || objfile_data (objfile, spu_overlay_data) != NULL)
return;
+ /* Consider only SPU objfiles. */
+ if (bfd_get_arch (objfile->obfd) != bfd_arch_spu)
+ return;
+
/* Check if this objfile has overlays. */
ovly_table = spu_get_overlay_table (objfile);
if (!ovly_table)
LONGEST len;
int rc, id;
+ if (gdbarch_bfd_arch_info (get_frame_arch (frame))->arch != bfd_arch_spu)
+ error (_("\"info spu\" is only supported on the SPU architecture."));
+
id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
xsnprintf (annex, sizeof annex, "%d/event_status", id);
len = target_read (¤t_target, TARGET_OBJECT_SPU, annex,
- buf, 0, sizeof buf);
+ buf, 0, (sizeof (buf) - 1));
if (len <= 0)
error (_("Could not read event_status."));
+ buf[len] = '\0';
event_status = strtoulst (buf, NULL, 16);
xsnprintf (annex, sizeof annex, "%d/event_mask", id);
len = target_read (¤t_target, TARGET_OBJECT_SPU, annex,
- buf, 0, sizeof buf);
+ buf, 0, (sizeof (buf) - 1));
if (len <= 0)
error (_("Could not read event_mask."));
+ buf[len] = '\0';
event_mask = strtoulst (buf, NULL, 16);
chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoEvent");
LONGEST len;
int rc, id;
+ if (gdbarch_bfd_arch_info (get_frame_arch (frame))->arch != bfd_arch_spu)
+ error (_("\"info spu\" is only supported on the SPU architecture."));
+
id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
xsnprintf (annex, sizeof annex, "%d/signal1", id);
xsnprintf (annex, sizeof annex, "%d/signal1_type", id);
len = target_read (¤t_target, TARGET_OBJECT_SPU, annex,
- buf, 0, sizeof buf);
+ buf, 0, (sizeof (buf) - 1));
if (len <= 0)
error (_("Could not read signal1_type."));
+ buf[len] = '\0';
signal1_type = strtoulst (buf, NULL, 16);
xsnprintf (annex, sizeof annex, "%d/signal2", id);
xsnprintf (annex, sizeof annex, "%d/signal2_type", id);
len = target_read (¤t_target, TARGET_OBJECT_SPU, annex,
- buf, 0, sizeof buf);
+ buf, 0, (sizeof (buf) - 1));
if (len <= 0)
error (_("Could not read signal2_type."));
+ buf[len] = '\0';
signal2_type = strtoulst (buf, NULL, 16);
chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoSignal");
printf_filtered (_("Signal 1 not pending "));
if (signal1_type)
- printf_filtered (_("(Type Overwrite)\n"));
- else
printf_filtered (_("(Type Or)\n"));
+ else
+ printf_filtered (_("(Type Overwrite)\n"));
if (signal2_pending)
printf_filtered (_("Signal 2 control word 0x%s "), phex (signal2, 4));
printf_filtered (_("Signal 2 not pending "));
if (signal2_type)
- printf_filtered (_("(Type Overwrite)\n"));
- else
printf_filtered (_("(Type Or)\n"));
+ else
+ printf_filtered (_("(Type Overwrite)\n"));
}
do_cleanups (chain);
LONGEST len;
int i, id;
+ if (gdbarch_bfd_arch_info (get_frame_arch (frame))->arch != bfd_arch_spu)
+ error (_("\"info spu\" is only supported on the SPU architecture."));
+
id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoMailbox");
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+ int *seq = alloca (nr * sizeof (int));
+ int done = 0;
struct cleanup *chain;
- int i;
+ int i, j;
+
+
+ /* Determine sequence in which to display (valid) entries. */
+ for (i = 0; i < nr; i++)
+ {
+ /* Search for the first valid entry all of whose
+ dependencies are met. */
+ for (j = 0; j < nr; j++)
+ {
+ ULONGEST mfc_cq_dw3;
+ ULONGEST dependencies;
+
+ if (done & (1 << (nr - 1 - j)))
+ continue;
+
+ mfc_cq_dw3 = extract_unsigned_integer (buf + 32*j + 24, 8);
+ if (!spu_mfc_get_bitfield (mfc_cq_dw3, 16, 16))
+ continue;
+
+ dependencies = spu_mfc_get_bitfield (mfc_cq_dw3, 0, nr - 1);
+ if ((dependencies & done) != dependencies)
+ continue;
+
+ seq[i] = j;
+ done |= 1 << (nr - 1 - j);
+ break;
+ }
+
+ if (j == nr)
+ break;
+ }
+
+ nr = i;
+
chain = make_cleanup_ui_out_table_begin_end (uiout, 10, nr, "dma_cmd");
ULONGEST mfc_cq_dw0;
ULONGEST mfc_cq_dw1;
ULONGEST mfc_cq_dw2;
- ULONGEST mfc_cq_dw3;
int mfc_cmd_opcode, mfc_cmd_tag, rclass_id, tclass_id;
int lsa, size, list_lsa, list_size, mfc_lsa, mfc_size;
ULONGEST mfc_ea;
/* Decode contents of MFC Command Queue Context Save/Restore Registers.
See "Cell Broadband Engine Registers V1.3", section 3.3.2.1. */
- mfc_cq_dw0 = extract_unsigned_integer (buf + 32*i, 8);
- mfc_cq_dw1 = extract_unsigned_integer (buf + 32*i + 8, 8);
- mfc_cq_dw2 = extract_unsigned_integer (buf + 32*i + 16, 8);
- mfc_cq_dw3 = extract_unsigned_integer (buf + 32*i + 24, 8);
+ mfc_cq_dw0 = extract_unsigned_integer (buf + 32*seq[i], 8);
+ mfc_cq_dw1 = extract_unsigned_integer (buf + 32*seq[i] + 8, 8);
+ mfc_cq_dw2 = extract_unsigned_integer (buf + 32*seq[i] + 16, 8);
list_lsa = spu_mfc_get_bitfield (mfc_cq_dw0, 0, 14);
list_size = spu_mfc_get_bitfield (mfc_cq_dw0, 15, 26);
LONGEST len;
int i, id;
+ if (gdbarch_bfd_arch_info (get_frame_arch (frame))->arch != bfd_arch_spu)
+ error (_("\"info spu\" is only supported on the SPU architecture."));
+
id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
xsnprintf (annex, sizeof annex, "%d/dma_info", id);
}
else
{
- const char *query_msg;
+ const char *query_msg = _("no query pending");
- switch (dma_info_type)
- {
- case 0: query_msg = _("no query pending"); break;
- case 1: query_msg = _("'any' query pending"); break;
- case 2: query_msg = _("'all' query pending"); break;
- default: query_msg = _("undefined query type"); break;
- }
+ if (dma_info_type & 4)
+ switch (dma_info_type & 3)
+ {
+ case 1: query_msg = _("'any' query pending"); break;
+ case 2: query_msg = _("'all' query pending"); break;
+ default: query_msg = _("undefined query type"); break;
+ }
printf_filtered (_("Tag-Group Status 0x%s\n"),
phex (dma_info_status, 4));
LONGEST len;
int i, id;
+ if (gdbarch_bfd_arch_info (get_frame_arch (frame))->arch != bfd_arch_spu)
+ error (_("\"info spu\" is only supported on the SPU architecture."));
+
id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
xsnprintf (annex, sizeof annex, "%d/proxydma_info", id);
{
const char *query_msg;
- switch (dma_info_type)
+ switch (dma_info_type & 3)
{
case 0: query_msg = _("no query pending"); break;
case 1: query_msg = _("'any' query pending"); break;
set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+ /* Address conversion. */
+ set_gdbarch_pointer_to_address (gdbarch, spu_pointer_to_address);
+ set_gdbarch_integer_to_address (gdbarch, spu_integer_to_address);
+
/* Inferior function calls. */
set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
set_gdbarch_frame_align (gdbarch, spu_frame_align);
+ set_gdbarch_frame_red_zone_size (gdbarch, 2000);
+ set_gdbarch_push_dummy_code (gdbarch, spu_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, spu_push_dummy_call);
- set_gdbarch_unwind_dummy_id (gdbarch, spu_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, spu_dummy_id);
set_gdbarch_return_value (gdbarch, spu_return_value);
/* Frame handling. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- frame_unwind_append_sniffer (gdbarch, spu_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &spu_frame_unwind);
frame_base_set_default (gdbarch, &spu_frame_base);
set_gdbarch_unwind_pc (gdbarch, spu_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, spu_unwind_sp);