/* Static function prototypes */
-static CORE_ADDR branch_dest (int opcode, int instr, CORE_ADDR pc,
- CORE_ADDR safety);
+static CORE_ADDR branch_dest (struct frame_info *frame, int opcode,
+ int instr, CORE_ADDR pc, CORE_ADDR safety);
static CORE_ADDR skip_prologue (CORE_ADDR, CORE_ADDR,
struct rs6000_framedata *);
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
int sim_regno;
- gdb_assert (0 <= reg && reg <= NUM_REGS + NUM_PSEUDO_REGS);
+ gdb_assert (0 <= reg
+ && reg <= gdbarch_num_regs (current_gdbarch)
+ + gdbarch_num_pseudo_regs (current_gdbarch));
sim_regno = tdep->sim_regno[reg];
if (sim_regno >= 0)
ppc_supply_reg (regcache, i, gregs, offset);
}
- if (regnum == -1 || regnum == PC_REGNUM)
- ppc_supply_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset);
+ if (regnum == -1 || regnum == gdbarch_pc_regnum (current_gdbarch))
+ ppc_supply_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
+ gregs, offsets->pc_offset);
if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
ppc_supply_reg (regcache, tdep->ppc_ps_regnum,
gregs, offsets->ps_offset);
ppc_collect_reg (regcache, i, gregs, offset);
}
- if (regnum == -1 || regnum == PC_REGNUM)
- ppc_collect_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset);
+ if (regnum == -1 || regnum == gdbarch_pc_regnum (current_gdbarch))
+ ppc_collect_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
+ gregs, offsets->pc_offset);
if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
ppc_collect_reg (regcache, tdep->ppc_ps_regnum,
gregs, offsets->ps_offset);
return 0;
}
-
-/* Fill in fi->saved_regs */
-
-struct frame_extra_info
-{
- /* Functions calling alloca() change the value of the stack
- pointer. We need to use initial stack pointer (which is saved in
- r31 by gcc) in such cases. If a compiler emits traceback table,
- then we should use the alloca register specified in traceback
- table. FIXME. */
- CORE_ADDR initial_sp; /* initial stack pointer. */
-};
-
/* Get the ith function argument for the current function. */
static CORE_ADDR
rs6000_fetch_pointer_argument (struct frame_info *frame, int argi,
/* Calculate the destination of a branch/jump. Return -1 if not a branch. */
static CORE_ADDR
-branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety)
+branch_dest (struct frame_info *frame, int opcode, int instr,
+ CORE_ADDR pc, CORE_ADDR safety)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
CORE_ADDR dest;
int immediate;
int absolute;
if (ext_op == 16) /* br conditional register */
{
- dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum) & ~3;
+ dest = get_frame_register_unsigned (frame, tdep->ppc_lr_regnum) & ~3;
/* If we are about to return from a signal handler, dest is
something like 0x3c90. The current frame is a signal handler
caller frame, upon completion of the sigreturn system call
execution will return to the saved PC in the frame. */
- if (dest < gdbarch_tdep (current_gdbarch)->text_segment_base)
- {
- struct frame_info *fi;
-
- fi = get_current_frame ();
- if (fi != NULL)
- dest = read_memory_addr (get_frame_base (fi) + SIG_FRAME_PC_OFFSET,
- gdbarch_tdep (current_gdbarch)->wordsize);
- }
+ if (dest < tdep->text_segment_base)
+ dest = read_memory_addr (get_frame_base (frame) + SIG_FRAME_PC_OFFSET,
+ tdep->wordsize);
}
else if (ext_op == 528) /* br cond to count reg */
{
- dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum) & ~3;
+ dest = get_frame_register_unsigned (frame, tdep->ppc_ctr_regnum) & ~3;
/* If we are about to execute a system call, dest is something
like 0x22fc or 0x3b00. Upon completion the system call
will return to the address in the link register. */
- if (dest < gdbarch_tdep (current_gdbarch)->text_segment_base)
- dest = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum) & ~3;
+ if (dest < tdep->text_segment_base)
+ dest = get_frame_register_unsigned (frame, tdep->ppc_lr_regnum) & ~3;
}
else
return -1;
default:
return -1;
}
- return (dest < gdbarch_tdep (current_gdbarch)->text_segment_base) ? safety : dest;
+ return (dest < tdep->text_segment_base) ? safety : dest;
}
static unsigned char big_breakpoint[] = { 0x7d, 0x82, 0x10, 0x08 };
static unsigned char little_breakpoint[] = { 0x08, 0x10, 0x82, 0x7d };
*bp_size = 4;
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
return big_breakpoint;
else
return little_breakpoint;
}
-/* AIX does not support PT_STEP. Simulate it. */
+/* Instruction masks used during single-stepping of atomic sequences. */
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+#define BC_MASK 0xfc000000
+#define BC_INSTRUCTION 0x40000000
+
+/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX
+ instruction and ending with a STWCX/STDCX instruction. If such a sequence
+ is found, attempt to step through it. A breakpoint is placed at the end of
+ the sequence. */
+
+static int
+deal_with_atomic_sequence (struct frame_info *frame)
+{
+ CORE_ADDR pc = get_frame_pc (frame);
+ CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR loc = pc;
+ CORE_ADDR branch_bp; /* Breakpoint at branch instruction's destination. */
+ CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence. */
+ int insn = read_memory_integer (loc, PPC_INSN_SIZE);
+ int insn_count;
+ int index;
+ int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
+ const int atomic_sequence_length = 16; /* Instruction sequence length. */
+ int opcode; /* Branch instruction's OPcode. */
+ int bc_insn_count = 0; /* Conditional branch instruction count. */
+
+ /* Assume all atomic sequences start with a lwarx/ldarx instruction. */
+ if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
+ && (insn & LWARX_MASK) != LDARX_INSTRUCTION)
+ return 0;
+
+ /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+ instructions. */
+ for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+ {
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ /* Assume that there is at most one conditional branch in the atomic
+ sequence. If a conditional branch is found, put a breakpoint in
+ its destination address. */
+ if ((insn & BC_MASK) == BC_INSTRUCTION)
+ {
+ if (bc_insn_count >= 1)
+ return 0; /* More than one conditional branch found, fallback
+ to the standard single-step code. */
+
+ opcode = insn >> 26;
+ branch_bp = branch_dest (frame, opcode, insn, pc, breaks[0]);
+
+ if (branch_bp != -1)
+ {
+ breaks[1] = branch_bp;
+ bc_insn_count++;
+ last_breakpoint++;
+ }
+ }
+
+ if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
+ || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
+ break;
+ }
+
+ /* Assume that the atomic sequence ends with a stwcx/stdcx instruction. */
+ if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
+ && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
+ return 0;
+
+ closing_insn = loc;
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ /* Insert a breakpoint right after the end of the atomic sequence. */
+ 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)))
+ last_breakpoint = 0;
+
+ /* Effectively inserts the breakpoints. */
+ for (index = 0; index <= last_breakpoint; index++)
+ insert_single_step_breakpoint (breaks[index]);
+
+ return 1;
+}
+
+/* AIX does not support PT_STEP. Simulate it. */
int
-rs6000_software_single_step (struct regcache *regcache)
+rs6000_software_single_step (struct frame_info *frame)
{
CORE_ADDR dummy;
int breakp_sz;
CORE_ADDR breaks[2];
int opcode;
- loc = read_pc ();
+ loc = get_frame_pc (frame);
insn = read_memory_integer (loc, 4);
+ if (deal_with_atomic_sequence (frame))
+ return 1;
+
breaks[0] = loc + breakp_sz;
opcode = insn >> 26;
- breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
+ breaks[1] = branch_dest (frame, opcode, insn, loc, breaks[0]);
/* Don't put two breakpoints on the same address. */
if (breaks[1] == breaks[0])
static int
bl_to_blrl_insn_p (CORE_ADDR pc, int insn)
{
- const int opcode = 18;
- const CORE_ADDR dest = branch_dest (opcode, insn, pc, -1);
+ CORE_ADDR dest;
+ int immediate;
+ int absolute;
int dest_insn;
- if (dest == -1)
- return 0; /* Should never happen, but just return zero to be safe. */
-
+ absolute = (int) ((insn >> 1) & 1);
+ immediate = ((insn & ~3) << 6) >> 6;
+ if (absolute)
+ dest = immediate;
+ else
+ dest = pc + immediate;
+
dest_insn = read_memory_integer (dest, 4);
if ((dest_insn & 0xfc00ffff) == 0x4c000021) /* blrl */
return 1;
struct value *arg = 0;
struct type *type;
- CORE_ADDR saved_sp;
+ ULONGEST saved_sp;
/* The calling convention this function implements assumes the
processor has floating-point registers. We shouldn't be using it
else
{
/* Argument can fit in one register. No problem. */
- int adj = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? reg_size - len : 0;
+ int adj = gdbarch_byte_order (current_gdbarch)
+ == BFD_ENDIAN_BIG ? reg_size - len : 0;
gdb_byte word[MAX_REGISTER_SIZE];
memset (word, 0, reg_size);
ran_out_of_registers_for_arguments:
- saved_sp = read_sp ();
+ regcache_cooked_read_unsigned (regcache,
+ gdbarch_sp_regnum (current_gdbarch),
+ &saved_sp);
/* Location for 8 parameters are always reserved. */
sp -= wordsize * 8;
to use this area. So, update %sp first before doing anything
else. */
- regcache_raw_write_signed (regcache, SP_REGNUM, sp);
+ regcache_raw_write_signed (regcache,
+ gdbarch_sp_regnum (current_gdbarch), sp);
/* If the last argument copied into the registers didn't fit there
completely, push the rest of it into stack. */
Not doing this can lead to conflicts with the kernel which thinks
that it still has control over this not-yet-allocated stack
region. */
- regcache_raw_write_signed (regcache, SP_REGNUM, sp);
+ regcache_raw_write_signed (regcache, gdbarch_sp_regnum (current_gdbarch), sp);
/* Set back chain properly. */
store_unsigned_integer (tmp_buffer, wordsize, saved_sp);
regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum, tocvalue);
}
- target_store_registers (-1);
+ target_store_registers (regcache, -1);
return sp;
}
branches, meaning that the link register doesn't get set.
Therefore, GDB's usual step_over_function () mechanism won't work.
- Instead, use the IN_SOLIB_RETURN_TRAMPOLINE and
- SKIP_TRAMPOLINE_CODE hooks in handle_inferior_event() to skip past
+ Instead, use the gdbarch_skip_trampoline_code and
+ gdbarch_skip_trampoline_code hooks in handle_inferior_event() to skip past
@FIX code. */
int
code that should be skipped. */
CORE_ADDR
-rs6000_skip_trampoline_code (CORE_ADDR pc)
+rs6000_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
unsigned int ii, op;
int rel;
}
/* If pc is in a shared library trampoline, return its target. */
- solib_target_pc = find_solib_trampoline_target (pc);
+ solib_target_pc = find_solib_trampoline_target (frame, pc);
if (solib_target_pc)
return solib_target_pc;
if (op != trampoline_code[ii])
return 0;
}
- ii = read_register (11); /* r11 holds destination addr */
+ ii = get_frame_register_unsigned (frame, 11); /* r11 holds destination addr */
pc = read_memory_addr (ii, gdbarch_tdep (current_gdbarch)->wordsize); /* (r11) value */
return pc;
}
+/* ISA-specific vector types. */
+
+static struct type *
+rs6000_builtin_type_vec64 (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->ppc_builtin_type_vec64)
+ {
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec64
+ {
+ int64_t uint64;
+ float v2_float[2];
+ int32_t v2_int32[2];
+ int16_t v4_int16[4];
+ int8_t v8_int8[8];
+ };
+#endif
+
+ struct type *t;
+
+ t = init_composite_type ("__ppc_builtin_type_vec64", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint64", builtin_type_int64);
+ append_composite_type_field (t, "v2_float",
+ init_vector_type (builtin_type_float, 2));
+ append_composite_type_field (t, "v2_int32",
+ init_vector_type (builtin_type_int32, 2));
+ append_composite_type_field (t, "v4_int16",
+ init_vector_type (builtin_type_int16, 4));
+ append_composite_type_field (t, "v8_int8",
+ init_vector_type (builtin_type_int8, 8));
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "ppc_builtin_type_vec64";
+ tdep->ppc_builtin_type_vec64 = t;
+ }
+
+ return tdep->ppc_builtin_type_vec64;
+}
+
+static struct type *
+rs6000_builtin_type_vec128 (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->ppc_builtin_type_vec128)
+ {
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec128
+ {
+ int128_t uint128;
+ float v4_float[4];
+ int32_t v4_int32[4];
+ int16_t v8_int16[8];
+ int8_t v16_int8[16];
+ };
+#endif
+
+ struct type *t;
+
+ t = init_composite_type ("__ppc_builtin_type_vec128", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint128", builtin_type_int128);
+ append_composite_type_field (t, "v4_float",
+ init_vector_type (builtin_type_float, 4));
+ append_composite_type_field (t, "v4_int32",
+ init_vector_type (builtin_type_int32, 4));
+ append_composite_type_field (t, "v8_int16",
+ init_vector_type (builtin_type_int16, 8));
+ append_composite_type_field (t, "v16_int8",
+ init_vector_type (builtin_type_int8, 16));
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "ppc_builtin_type_vec128";
+ tdep->ppc_builtin_type_vec128 = t;
+ }
+
+ return tdep->ppc_builtin_type_vec128;
+}
+
/* Return the size of register REG when words are WORDSIZE bytes long. If REG
isn't available with that word size, return 0. */
return builtin_type_uint32;
case 8:
if (tdep->ppc_ev0_regnum <= n && n <= tdep->ppc_ev31_regnum)
- return builtin_type_vec64;
+ return rs6000_builtin_type_vec64 (gdbarch);
else
return builtin_type_uint64;
break;
case 16:
- return builtin_type_vec128;
+ return rs6000_builtin_type_vec128 (gdbarch);
break;
default:
internal_error (__FILE__, __LINE__, _("Register %d size %d unknown"),
int vector_p;
int general_p;
- if (REGISTER_NAME (regnum) == NULL
- || *REGISTER_NAME (regnum) == '\0')
+ if (gdbarch_register_name (current_gdbarch, regnum) == NULL
+ || *gdbarch_register_name (current_gdbarch, regnum) == '\0')
return 0;
if (group == all_reggroup)
return 1;
|| regnum == tdep->ppc_lr_regnum
|| regnum == tdep->ppc_ctr_regnum
|| regnum == tdep->ppc_xer_regnum
- || regnum == PC_REGNUM);
+ || regnum == gdbarch_pc_regnum (current_gdbarch));
if (group == general_reggroup)
return general_p;
reg_index = ev_reg - tdep->ppc_ev0_regnum;
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (current_gdbarch) == 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);
if (!info->disassembler_options)
info->disassembler_options = "any";
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
return print_insn_big_powerpc (memaddr, info);
else
return print_insn_little_powerpc (memaddr, info);
static CORE_ADDR
rs6000_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- return frame_unwind_register_unsigned (next_frame, PC_REGNUM);
+ return frame_unwind_register_unsigned (next_frame,
+ gdbarch_pc_regnum (current_gdbarch));
}
static struct frame_id
rs6000_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- return frame_id_build (frame_unwind_register_unsigned (next_frame,
- SP_REGNUM),
- frame_pc_unwind (next_frame));
+ return frame_id_build (frame_unwind_register_unsigned
+ (next_frame, gdbarch_sp_regnum (current_gdbarch)),
+ frame_pc_unwind (next_frame));
}
struct rs6000_frame_cache
->frame pointed to the outer-most address of the frame. In
the mean time, the address of the prev frame is used as the
base address of this frame. */
- cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+ cache->base = frame_unwind_register_unsigned
+ (next_frame, gdbarch_sp_regnum (current_gdbarch));
/* If the function appears to be frameless, check a couple of likely
indicators that we have simply failed to find the frame setup.
/* Frameless really means stackless. */
cache->base = read_memory_addr (cache->base, wordsize);
- trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
+ trad_frame_set_value (cache->saved_regs,
+ gdbarch_sp_regnum (current_gdbarch), cache->base);
/* if != -1, fdata.saved_fpr is the smallest number of saved_fpr.
All fpr's from saved_fpr to fp31 are saved. */
if (fdata.lr_offset != 0)
cache->saved_regs[tdep->ppc_lr_regnum].addr = cache->base + fdata.lr_offset;
/* The PC is found in the link register. */
- cache->saved_regs[PC_REGNUM] = cache->saved_regs[tdep->ppc_lr_regnum];
+ cache->saved_regs[gdbarch_pc_regnum (current_gdbarch)] =
+ cache->saved_regs[tdep->ppc_lr_regnum];
/* If != 0, fdata.vrsave_offset is the offset from the frame that
holds the VRSAVE. */
if (fdata.alloca_reg < 0)
/* If no alloca register used, then fi->frame is the value of the
%sp for this frame, and it is good enough. */
- cache->initial_sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+ cache->initial_sp = frame_unwind_register_unsigned
+ (next_frame, gdbarch_sp_regnum (current_gdbarch));
else
cache->initial_sp = frame_unwind_register_unsigned (next_frame,
fdata.alloca_reg);
info.bfd_arch_info = bfd_get_arch_info (&abfd);
mach = info.bfd_arch_info->mach;
}
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ tdep = XCALLOC (1, struct gdbarch_tdep);
tdep->wordsize = wordsize;
/* For e500 executables, the apuinfo section is of help here. Such
else
set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc);
- set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
-
set_gdbarch_num_regs (gdbarch, v->nregs);
set_gdbarch_num_pseudo_regs (gdbarch, v->npregs);
set_gdbarch_register_name (gdbarch, rs6000_register_name);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
+ /* Handles single stepping of atomic sequences. */
+ set_gdbarch_software_single_step (gdbarch, deal_with_atomic_sequence);
+
/* Handle the 64-bit SVR4 minimal-symbol convention of using "FN"
for the descriptor and ".FN" for the entry-point -- a user
specifying "break FN" will unexpectedly end up with a breakpoint