/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "solib-svr4.h"
#include "ppc-tdep.h"
+#include "ppc-ravenscar-thread.h"
#include "gdb_assert.h"
#include "dis-asm.h"
/* Determine if regnum is a POWER7 Extended FP register. */
#define IS_EFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_efpr0_regnum >= 0 \
&& (regnum) >= (tdep)->ppc_efpr0_regnum \
- && (regnum) < (tdep)->ppc_efpr0_regnum + ppc_num_fprs)
+ && (regnum) < (tdep)->ppc_efpr0_regnum + ppc_num_efprs)
/* The list of available "set powerpc ..." and "show powerpc ..."
commands. */
static enum auto_boolean powerpc_soft_float_global = AUTO_BOOLEAN_AUTO;
/* The vector ABI to use. Keep this in sync with powerpc_vector_abi. */
-static const char *powerpc_vector_strings[] =
+static const char *const powerpc_vector_strings[] =
{
"auto",
"generic",
/* Sequence of bytes for breakpoint instruction. */
-const static unsigned char *
+static const unsigned char *
rs6000_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
int *bp_size)
{
its destination address. */
if ((insn & BRANCH_MASK) == BC_INSN)
{
- int immediate = ((insn & ~3) << 16) >> 16;
- int absolute = ((insn >> 1) & 1);
+ int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
+ int absolute = insn & 2;
if (bc_insn_count >= 1)
return 0; /* More than one conditional branch found, fallback
if (absolute)
breaks[1] = immediate;
else
- breaks[1] = pc + immediate;
+ breaks[1] = loc + immediate;
bc_insn_count++;
last_breakpoint++;
breaks[0] = loc;
/* Check for duplicated breakpoints. Check also for a breakpoint
- placed (branch instruction's destination) at the stwcx/stdcx
- instruction, this resets the reservation and take us back to the
- lwarx/ldarx instruction at the beginning of the atomic sequence. */
- if (last_breakpoint && ((breaks[1] == breaks[0])
- || (breaks[1] == closing_insn)))
+ placed (branch instruction's destination) anywhere in sequence. */
+ if (last_breakpoint
+ && (breaks[1] == breaks[0]
+ || (breaks[1] >= pc && breaks[1] <= closing_insn)))
last_breakpoint = 0;
/* Effectively inserts the breakpoints. */
/* Set up frame pointer */
}
+ else if (op == 0x603d0000) /* oril r29, r1, 0x0 */
+ {
+ fdata->frameless = 0;
+ framep = 1;
+ fdata->alloca_reg = (tdep->ppc_gp0_regnum + 29);
+ continue;
+
+ /* Another way to set up the frame pointer. */
+ }
else if (op == 0x603f0000 /* oril r31, r1, 0x0 */
|| op == 0x7c3f0b78)
{ /* mr r31, r1 */
{
CORE_ADDR displ = op & BL_DISPLACEMENT_MASK;
CORE_ADDR call_dest = pc + 4 + displ;
- struct minimal_symbol *s = lookup_minimal_symbol_by_pc (call_dest);
+ struct bound_minimal_symbol s = lookup_minimal_symbol_by_pc (call_dest);
/* We check for ___eabi (three leading underscores) in addition
to __eabi in case the GCC option "-fleading-underscore" was
used to compile the program. */
- if (s != NULL
- && SYMBOL_LINKAGE_NAME (s) != NULL
- && (strcmp (SYMBOL_LINKAGE_NAME (s), "__eabi") == 0
- || strcmp (SYMBOL_LINKAGE_NAME (s), "___eabi") == 0))
+ if (s.minsym != NULL
+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL
+ && (strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__eabi") == 0
+ || strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "___eabi") == 0))
pc += 4;
}
return pc;
static int
rs6000_in_solib_return_trampoline (struct gdbarch *gdbarch,
- CORE_ADDR pc, char *name)
+ CORE_ADDR pc, const char *name)
{
return name && !strncmp (name, "@FIX", 4);
}
unsigned int ii, op;
int rel;
CORE_ADDR solib_target_pc;
- struct minimal_symbol *msymbol;
+ struct bound_minimal_symbol msymbol;
static unsigned trampoline_code[] =
{
/* Check for bigtoc fixup code. */
msymbol = lookup_minimal_symbol_by_pc (pc);
- if (msymbol
+ if (msymbol.minsym
&& rs6000_in_solib_return_trampoline (gdbarch, pc,
- SYMBOL_LINKAGE_NAME (msymbol)))
+ SYMBOL_LINKAGE_NAME (msymbol.minsym)))
{
/* Double-check that the third instruction from PC is relative "b". */
op = read_memory_integer (pc + 8, 4, byte_order);
!= TYPE_LENGTH (builtin_type (gdbarch)->builtin_double));
}
-static void
+static int
rs6000_register_to_value (struct frame_info *frame,
int regnum,
struct type *type,
- gdb_byte *to)
+ gdb_byte *to,
+ int *optimizedp, int *unavailablep)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
gdb_byte from[MAX_REGISTER_SIZE];
gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
- get_frame_register (frame, regnum, from);
+ if (!get_frame_register_bytes (frame, regnum, 0,
+ register_size (gdbarch, regnum),
+ from, optimizedp, unavailablep))
+ return 0;
+
convert_typed_floating (from, builtin_type (gdbarch)->builtin_double,
to, type);
+ *optimizedp = *unavailablep = 0;
+ return 1;
}
static void
put_frame_register (frame, regnum, to);
}
+ /* The type of a function that moves the value of REG between CACHE
+ or BUF --- in either direction. */
+typedef enum register_status (*move_ev_register_func) (struct regcache *,
+ int, void *);
+
/* Move SPE vector register values between a 64-bit buffer and the two
32-bit raw register halves in a regcache. This function handles
both splitting a 64-bit value into two 32-bit halves, and joining
MOVE, since this function can't tell at compile-time which of
REGCACHE or BUFFER is acting as the source of the data. If C had
co-variant type qualifiers, ... */
-static void
-e500_move_ev_register (void (*move) (struct regcache *regcache,
- int regnum, gdb_byte *buf),
- struct regcache *regcache, int ev_reg,
- gdb_byte *buffer)
+
+static enum register_status
+e500_move_ev_register (move_ev_register_func move,
+ struct regcache *regcache, int ev_reg, void *buffer)
{
struct gdbarch *arch = get_regcache_arch (regcache);
struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
int reg_index;
gdb_byte *byte_buffer = buffer;
+ enum register_status status;
gdb_assert (IS_SPE_PSEUDOREG (tdep, ev_reg));
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
{
- move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, byte_buffer);
- move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer + 4);
+ status = move (regcache, tdep->ppc_ev0_upper_regnum + reg_index,
+ byte_buffer);
+ if (status == REG_VALID)
+ status = move (regcache, tdep->ppc_gp0_regnum + reg_index,
+ byte_buffer + 4);
}
else
{
- move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer);
- move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, byte_buffer + 4);
+ status = move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer);
+ if (status == REG_VALID)
+ status = move (regcache, tdep->ppc_ev0_upper_regnum + reg_index,
+ byte_buffer + 4);
}
+
+ return status;
}
-static void
+static enum register_status
+do_regcache_raw_read (struct regcache *regcache, int regnum, void *buffer)
+{
+ return regcache_raw_read (regcache, regnum, buffer);
+}
+
+static enum register_status
+do_regcache_raw_write (struct regcache *regcache, int regnum, void *buffer)
+{
+ regcache_raw_write (regcache, regnum, buffer);
+
+ return REG_VALID;
+}
+
+static enum register_status
e500_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
{
- e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer);
+ return e500_move_ev_register (do_regcache_raw_read, regcache, reg_nr, buffer);
}
static void
e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, const gdb_byte *buffer)
{
- e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *))
- regcache_raw_write,
- regcache, reg_nr, (gdb_byte *) buffer);
+ e500_move_ev_register (do_regcache_raw_write, regcache,
+ reg_nr, (void *) buffer);
}
/* Read method for DFP pseudo-registers. */
-static void
+static enum register_status
dfp_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int reg_index = reg_nr - tdep->ppc_dl0_regnum;
+ enum register_status status;
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
/* Read two FP registers to form a whole dl register. */
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- 2 * reg_index, buffer);
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- 2 * reg_index + 1, buffer + 8);
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
+ if (status == REG_VALID)
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
}
else
{
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- 2 * reg_index + 1, buffer + 8);
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- 2 * reg_index, buffer);
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
+ if (status == REG_VALID)
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
}
+
+ return status;
}
/* Write method for DFP pseudo-registers. */
}
/* Read method for POWER7 VSX pseudo-registers. */
-static void
+static enum register_status
vsx_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int reg_index = reg_nr - tdep->ppc_vsr0_regnum;
+ enum register_status status;
/* Read the portion that overlaps the VMX registers. */
if (reg_index > 31)
- regcache_raw_read (regcache, tdep->ppc_vr0_regnum +
- reg_index - 32, buffer);
+ status = regcache_raw_read (regcache, tdep->ppc_vr0_regnum +
+ reg_index - 32, buffer);
else
/* Read the portion that overlaps the FPR registers. */
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- reg_index, buffer);
- regcache_raw_read (regcache, tdep->ppc_vsr0_upper_regnum +
- reg_index, buffer + 8);
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ reg_index, buffer);
+ if (status == REG_VALID)
+ status = regcache_raw_read (regcache, tdep->ppc_vsr0_upper_regnum +
+ reg_index, buffer + 8);
}
else
{
- regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
- reg_index, buffer + 8);
- regcache_raw_read (regcache, tdep->ppc_vsr0_upper_regnum +
- reg_index, buffer);
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ reg_index, buffer + 8);
+ if (status == REG_VALID)
+ status = regcache_raw_read (regcache, tdep->ppc_vsr0_upper_regnum +
+ reg_index, buffer);
}
+
+ return status;
}
/* Write method for POWER7 VSX pseudo-registers. */
}
/* Read method for POWER7 Extended FP pseudo-registers. */
-static void
+static enum register_status
efpr_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
- /* Read the portion that overlaps the VMX registers. */
- regcache_raw_read (regcache, tdep->ppc_vr0_regnum +
- reg_index, buffer);
+ /* Read the portion that overlaps the VMX register. */
+ return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+ register_size (gdbarch, reg_nr), buffer);
}
/* Write method for POWER7 Extended FP pseudo-registers. */
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
- /* Write the portion that overlaps the VMX registers. */
- regcache_raw_write (regcache, tdep->ppc_vr0_regnum +
- reg_index, buffer);
+ /* Write the portion that overlaps the VMX register. */
+ regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+ register_size (gdbarch, reg_nr), buffer);
}
-static void
+static enum register_status
rs6000_pseudo_register_read (struct gdbarch *gdbarch,
struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
gdb_assert (regcache_arch == gdbarch);
if (IS_SPE_PSEUDOREG (tdep, reg_nr))
- e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+ return e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
else if (IS_DFP_PSEUDOREG (tdep, reg_nr))
- dfp_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+ return dfp_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
else if (IS_VSX_PSEUDOREG (tdep, reg_nr))
- vsx_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+ return vsx_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
else if (IS_EFP_PSEUDOREG (tdep, reg_nr))
- efpr_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+ return efpr_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
else
internal_error (__FILE__, __LINE__,
_("rs6000_pseudo_register_read: "
else if (77 <= num && num <= 108)
return tdep->ppc_vr0_regnum + (num - 77);
else if (1200 <= num && num < 1200 + 32)
- return tdep->ppc_ev0_regnum + (num - 1200);
+ return tdep->ppc_ev0_upper_regnum + (num - 1200);
else
switch (num)
{
else if (1124 <= num && num < 1124 + 32)
return tdep->ppc_vr0_regnum + (num - 1124);
else if (1200 <= num && num < 1200 + 32)
- return tdep->ppc_ev0_regnum + (num - 1200);
+ return tdep->ppc_ev0_upper_regnum + (num - 1200);
else
switch (num)
{
static int
gdb_print_insn_powerpc (bfd_vma memaddr, disassemble_info *info)
{
- if (!info->disassembler_options)
- {
- /* When debugging E500 binaries and disassembling code containing
- E500-specific (SPE) instructions, one sometimes sees AltiVec
- instructions instead. The opcode spaces for SPE instructions
- and AltiVec instructions overlap, and specifiying the "any" cpu
- looks for AltiVec instructions first. If we know we're
- debugging an E500 binary, however, we can specify the "e500x2"
- cpu and get much more sane disassembly output. */
- if (info->mach == bfd_mach_ppc_e500)
- info->disassembler_options = "e500x2";
- else
- info->disassembler_options = "any";
- }
-
if (info->endian == BFD_ENDIAN_BIG)
return print_insn_big_powerpc (memaddr, info);
else
static const struct frame_unwind rs6000_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
rs6000_frame_this_id,
rs6000_frame_prev_register,
NULL,
enum bfd_architecture arch;
unsigned long mach;
bfd abfd;
- asection *sect;
enum auto_boolean soft_float_flag = powerpc_soft_float_global;
int soft_float;
enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global;
gdb_assert (gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch) == cur_reg);
+ /* Register the ravenscar_arch_ops. */
+ if (mach == bfd_mach_ppc_e500)
+ register_e500_ravenscar_ops (gdbarch);
+ else
+ register_ppc_ravenscar_ops (gdbarch);
+
return gdbarch;
}
fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value);
}
+/* Read a PPC instruction from memory. */
+
+static unsigned int
+read_insn (struct frame_info *frame, CORE_ADDR pc)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ return read_memory_unsigned_integer (pc, 4, byte_order);
+}
+
+/* Return non-zero if the instructions at PC match the series
+ described in PATTERN, or zero otherwise. PATTERN is an array of
+ 'struct ppc_insn_pattern' objects, terminated by an entry whose
+ mask is zero.
+
+ When the match is successful, fill INSN[i] with what PATTERN[i]
+ matched. If PATTERN[i] is optional, and the instruction wasn't
+ present, set INSN[i] to 0 (which is not a valid PPC instruction).
+ INSN should have as many elements as PATTERN. Note that, if
+ PATTERN contains optional instructions which aren't present in
+ memory, then INSN will have holes, so INSN[i] isn't necessarily the
+ i'th instruction in memory. */
+
+int
+ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc,
+ struct ppc_insn_pattern *pattern,
+ unsigned int *insns)
+{
+ int i;
+ unsigned int insn;
+
+ for (i = 0, insn = 0; pattern[i].mask; i++)
+ {
+ if (insn == 0)
+ insn = read_insn (frame, pc);
+ insns[i] = 0;
+ if ((insn & pattern[i].mask) == pattern[i].data)
+ {
+ insns[i] = insn;
+ pc += 4;
+ insn = 0;
+ }
+ else if (!pattern[i].optional)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return the 'd' field of the d-form instruction INSN, properly
+ sign-extended. */
+
+CORE_ADDR
+ppc_insn_d_field (unsigned int insn)
+{
+ return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000);
+}
+
+/* Return the 'ds' field of the ds-form instruction INSN, with the two
+ zero bits concatenated at the right, and properly
+ sign-extended. */
+
+CORE_ADDR
+ppc_insn_ds_field (unsigned int insn)
+{
+ return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
+}
+
/* Initialization code. */
/* -Wmissing-prototypes */