/* SPU target-dependent code for GDB, the GNU debugger.
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
Based on a port by Sid Manning <sid@us.ibm.com>.
return builtin_type (gdbarch)->builtin_uint32;
default:
- internal_error (__FILE__, __LINE__, "invalid regnum");
+ internal_error (__FILE__, __LINE__, _("invalid regnum"));
}
}
return id;
}
-static ULONGEST
-spu_lslr (int id)
-{
- gdb_byte buf[32];
- char annex[32];
-
- if (id == -1)
- return SPU_LS_SIZE - 1;
-
- xsnprintf (annex, sizeof annex, "%d/lslr", id);
- memset (buf, 0, sizeof buf);
- target_read (¤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)
{
struct type *type, const gdb_byte *buf)
{
int id = spu_gdbarch_id (gdbarch);
- ULONGEST lslr = spu_lslr (id);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST addr
= extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
if (TYPE_ADDRESS_CLASS_1 (type))
return addr;
- return addr? SPUADDR (id, addr & lslr) : 0;
+ return addr? SPUADDR (id, addr) : 0;
}
static CORE_ADDR
struct type *type, const gdb_byte *buf)
{
int id = spu_gdbarch_id (gdbarch);
- ULONGEST lslr = spu_lslr (id);
ULONGEST addr = unpack_long (type, buf);
- return SPUADDR (id, addr & lslr);
+ return SPUADDR (id, addr);
}
}
else
{
- /* ??? We don't really know ... */
+ /* ??? We don't really know ... */
*reg = SPU_SP_REGNUM;
*offset = 0;
}
{
CORE_ADDR reg;
LONGEST backchain;
+ ULONGEST lslr;
int status;
+ /* Get local store limit. */
+ lslr = get_frame_register_unsigned (this_frame, SPU_LSLR_REGNUM);
+ if (!lslr)
+ lslr = (ULONGEST) -1;
+
/* Get the backchain. */
reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM);
status = safe_read_memory_integer (SPUADDR (id, reg), 4, byte_order,
/* A zero backchain terminates the frame chain. Also, sanity
check against the local store size limit. */
- if (status && backchain > 0 && backchain < SPU_LS_SIZE)
+ if (status && backchain > 0 && backchain <= lslr)
{
/* Assume the link register is saved into its slot. */
- if (backchain + 16 < SPU_LS_SIZE)
- info->saved_regs[SPU_LR_REGNUM].addr = SPUADDR (id, backchain + 16);
+ if (backchain + 16 <= lslr)
+ info->saved_regs[SPU_LR_REGNUM].addr = SPUADDR (id,
+ backchain + 16);
/* Frame bases. */
info->frame_base = SPUADDR (id, backchain);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
- error ("Cannot set function return value.");
+ error (_("Cannot set function return value."));
break;
}
}
break;
case RETURN_VALUE_STRUCT_CONVENTION:
- error ("Function return value unknown.");
+ error (_("Function return value unknown."));
break;
}
}
/* Breakpoints. */
static const gdb_byte *
-spu_breakpoint_from_pc (struct gdbarch *gdbarch, 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 };
return breakpoint;
}
+static int
+spu_memory_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ /* We work around a problem in combined Cell/B.E. debugging here. Consider
+ that in a combined application, we have some breakpoints inserted in SPU
+ code, and now the application forks (on the PPU side). GDB common code
+ will assume that the fork system call copied all breakpoints into the new
+ process' address space, and that all those copies now need to be removed
+ (see breakpoint.c:detach_breakpoints).
+
+ While this is certainly true for PPU side breakpoints, it is not true
+ for SPU side breakpoints. fork will clone the SPU context file
+ descriptors, so that all the existing SPU contexts are in accessible
+ in the new process. However, the contents of the SPU contexts themselves
+ are *not* cloned. Therefore the effect of detach_breakpoints is to
+ remove SPU breakpoints from the *original* SPU context's local store
+ -- this is not the correct behaviour.
+
+ The workaround is to check whether the PID we are asked to remove this
+ breakpoint from (i.e. ptid_get_pid (inferior_ptid)) is different from the
+ PID of the current inferior (i.e. current_inferior ()->pid). This is only
+ true in the context of detach_breakpoints. If so, we simply do nothing.
+ [ Note that for the fork child process, it does not matter if breakpoints
+ remain inserted, because those SPU contexts are not runnable anyway --
+ the Linux kernel allows only the original process to invoke spu_run. */
+
+ if (ptid_get_pid (inferior_ptid) != current_inferior ()->pid)
+ return 0;
+
+ return default_memory_remove_breakpoint (gdbarch, bp_tgt);
+}
+
/* Software single-stepping support. */
unsigned int insn;
int offset, reg;
gdb_byte buf[4];
+ ULONGEST lslr;
pc = get_frame_pc (frame);
return 1;
insn = extract_unsigned_integer (buf, 4, byte_order);
+ /* Get local store limit. */
+ lslr = get_frame_register_unsigned (frame, SPU_LSLR_REGNUM);
+ if (!lslr)
+ lslr = (ULONGEST) -1;
+
/* Next sequential instruction is at PC + 4, except if the current
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 = (SPUADDR_ADDR (pc) + 8) & (SPU_LS_SIZE - 1);
+ next_pc = (SPUADDR_ADDR (pc) + 8) & lslr;
else
- next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1);
+ next_pc = (SPUADDR_ADDR (pc) + 4) & lslr;
insert_single_step_breakpoint (gdbarch,
aspace, SPUADDR (SPUADDR_SPU (pc), next_pc));
target += extract_unsigned_integer (buf, 4, byte_order) & -4;
}
- target = target & (SPU_LS_SIZE - 1);
+ target = target & lslr;
if (target != next_pc)
insert_single_step_breakpoint (gdbarch, aspace,
SPUADDR (SPUADDR_SPU (pc), target));
static int
gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
{
- /* The opcodes disassembler does 18-bit address arithmetic. Make sure the
- SPU ID encoded in the high bits is added back when we call print_address. */
+ /* The opcodes disassembler does 18-bit address arithmetic. Make
+ sure the SPU ID encoded in the high bits is added back when we
+ call print_address. */
struct disassemble_info spu_info = *info;
struct spu_dis_asm_data data;
data.gdbarch = info->application_data;
_ovly_table should never change.
- Both tables are aligned to a 16-byte boundary, the symbols _ovly_table
- and _ovly_buf_table are of type STT_OBJECT and their size set to the size
- of the respective array. buf in _ovly_table is an index into _ovly_buf_table.
+ Both tables are aligned to a 16-byte boundary, the symbols
+ _ovly_table and _ovly_buf_table are of type STT_OBJECT and their
+ size set to the size of the respective array. buf in _ovly_table is
+ an index into _ovly_buf_table.
- mapped is an index into _ovly_table. Both the mapped and buf indices start
+ mapped is an index into _ovly_table. Both the mapped and buf indices start
from one to reference the first entry in their respective tables. */
/* Using the per-objfile private data mechanism, we store for each
if (!ovly_table_msym)
return NULL;
- ovly_buf_table_msym = lookup_minimal_symbol ("_ovly_buf_table", NULL, objfile);
+ ovly_buf_table_msym = lookup_minimal_symbol ("_ovly_buf_table",
+ NULL, objfile);
if (!ovly_buf_table_msym)
return NULL;
/* Whenever a new objfile is loaded, read the target's _ovly_table.
If there is one, go through all sections and make sure for non-
overlay sections LMA equals VMA, while for overlay sections LMA
- is larger than local store size. */
+ is larger than SPU_OVERLAY_LMA. */
static void
spu_overlay_new_objfile (struct objfile *objfile)
{
if (ovly_table[ndx].mapped_ptr == 0)
bfd_section_lma (obfd, bsect) = bfd_section_vma (obfd, bsect);
else
- bfd_section_lma (obfd, bsect) = bsect->filepos + SPU_LS_SIZE;
+ bfd_section_lma (obfd, bsect) = SPU_OVERLAY_LMA + bsect->filepos;
}
}
/* Use a numerical address for the set_breakpoint command to avoid having
the breakpoint re-set incorrectly. */
xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
- set_breakpoint (get_objfile_arch (objfile),
- buf, NULL /* condition */,
- 0 /* hardwareflag */, 1 /* tempflag */,
- -1 /* thread */, 0 /* ignore_count */,
- 0 /* pending */, 1 /* enabled */);
+ create_breakpoint (get_objfile_arch (objfile), buf /* arg */,
+ NULL /* cond_string */, -1 /* thread */,
+ 0 /* parse_condition_and_thread */, 1 /* tempflag */,
+ bp_breakpoint /* type_wanted */,
+ 0 /* ignore_count */,
+ AUTO_BOOLEAN_FALSE /* pending_break_support */,
+ NULL /* ops */, 0 /* from_tty */, 1 /* enabled */,
+ 0 /* internal */);
}
static void
info_spu_command (char *args, int from_tty)
{
- printf_unfiltered (_("\"info spu\" must be followed by the name of an SPU facility.\n"));
+ printf_unfiltered (_("\"info spu\" must be followed by "
+ "the name of an SPU facility.\n"));
help_list (infospucmdlist, "info spu ", -1, gdb_stdout);
}
/* Breakpoints. */
set_gdbarch_decr_pc_after_break (gdbarch, 4);
set_gdbarch_breakpoint_from_pc (gdbarch, spu_breakpoint_from_pc);
+ set_gdbarch_memory_remove_breakpoint (gdbarch, spu_memory_remove_breakpoint);
set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
set_gdbarch_software_single_step (gdbarch, spu_software_single_step);
set_gdbarch_get_longjmp_target (gdbarch, spu_get_longjmp_target);