#define X_IMM22(i) ((i) & 0x3fffff)
#define X_OP3(i) (((i) >> 19) & 0x3f)
#define X_RS1(i) (((i) >> 14) & 0x1f)
+#define X_RS2(i) ((i) & 0x1f)
#define X_I(i) (((i) >> 13) & 1)
/* Sign extension macros. */
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
}
\f
-/* Return the contents if register REGNUM as an address. */
-
-CORE_ADDR
-sparc_address_from_register (int regnum)
-{
- ULONGEST addr;
-
- regcache_cooked_read_unsigned (current_regcache, regnum, &addr);
- return addr;
-}
-\f
-
/* The functions on this page are intended to be used to classify
function arguments. */
CORE_ADDR funcaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
{
*bp_addr = sp - 4;
*real_pc = funcaddr;
return cache;
}
+/* GCC generates several well-known sequences of instructions at the begining
+ of each function prologue when compiling with -fstack-check. If one of
+ such sequences starts at START_PC, then return the address of the
+ instruction immediately past this sequence. Otherwise, return START_PC. */
+
+static CORE_ADDR
+sparc_skip_stack_check (const CORE_ADDR start_pc)
+{
+ CORE_ADDR pc = start_pc;
+ unsigned long insn;
+ int offset_stack_checking_sequence = 0;
+
+ /* With GCC, all stack checking sequences begin with the same two
+ instructions. */
+
+ /* sethi <some immediate>,%g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* sub %sp, %g1, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1))
+ return start_pc;
+
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+
+ /* First possible sequence:
+ [first two instructions above]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1 - some immediate] */
+ if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ /* Valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Second possible sequence: A small number of probes.
+ [first two instructions above]
+ clr [%g1]
+ add %g1, -<some immediate>, %g1
+ clr [%g1]
+ [repeat the two instructions above any (small) number of times]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1] */
+ else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ while (1)
+ {
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ break;
+
+ /* clr [%g1] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+ return start_pc;
+ }
+
+ /* clr [%g1 - some immediate] */
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Third sequence: A probing loop.
+ [first two instructions above]
+ sethi <some immediate>, %g4
+ sub %g1, %g4, %g4
+ cmp %g1, %g4
+ be <disp>
+ add %g1, -<some immediate>, %g1
+ ba <disp>
+ clr [%g1]
+ clr [%g4 - some immediate] */
+
+ /* sethi <some immediate>, %g4 */
+ else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+ {
+ /* sub %g1, %g4, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* cmp %g1, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* be <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1))
+ return start_pc;
+
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* ba <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8))
+ return start_pc;
+
+ /* clr [%g1] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+ return start_pc;
+
+ /* clr [%g4 - some immediate] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 4 && X_RD (insn) == 0))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* No stack check code in our prologue, return the start_pc. */
+ return start_pc;
+}
+
CORE_ADDR
sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
struct sparc_frame_cache *cache)
int offset = 0;
int dest = -1;
+ pc = sparc_skip_stack_check (pc);
+
if (current_pc <= pc)
return current_pc;
software single-step mechanism. */
static CORE_ADDR
-sparc_analyze_control_transfer (struct gdbarch *arch,
+sparc_analyze_control_transfer (struct frame_info *frame,
CORE_ADDR pc, CORE_ADDR *npc)
{
unsigned long insn = sparc_fetch_instruction (pc);
else if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3a)
{
/* Trap instruction (TRAP). */
- return gdbarch_tdep (arch)->step_trap (insn);
+ return gdbarch_tdep (get_frame_arch (frame))->step_trap (frame, insn);
}
/* FIXME: Handle DONE and RETRY instructions. */
}
static CORE_ADDR
-sparc_step_trap (unsigned long insn)
+sparc_step_trap (struct frame_info *frame, unsigned long insn)
{
return 0;
}
-void
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+int
+sparc_software_single_step (struct frame_info *frame)
{
- struct gdbarch *arch = current_gdbarch;
+ struct gdbarch *arch = get_frame_arch (frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
CORE_ADDR npc, nnpc;
- if (insert_breakpoints_p)
- {
- CORE_ADDR pc, orig_npc;
+ CORE_ADDR pc, orig_npc;
- pc = sparc_address_from_register (tdep->pc_regnum);
- orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
+ pc = get_frame_register_unsigned (frame, tdep->pc_regnum);
+ orig_npc = npc = get_frame_register_unsigned (frame, tdep->npc_regnum);
- /* Analyze the instruction at PC. */
- nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
- if (npc != 0)
- insert_single_step_breakpoint (npc);
+ /* Analyze the instruction at PC. */
+ nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
+ if (npc != 0)
+ insert_single_step_breakpoint (npc);
- if (nnpc != 0)
- insert_single_step_breakpoint (nnpc);
+ if (nnpc != 0)
+ insert_single_step_breakpoint (nnpc);
- /* Assert that we have set at least one breakpoint, and that
- they're not set at the same spot - unless we're going
- from here straight to NULL, i.e. a call or jump to 0. */
- gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
- gdb_assert (nnpc != npc || orig_npc == 0);
- }
- else
- remove_single_step_breakpoints ();
+ /* Assert that we have set at least one breakpoint, and that
+ they're not set at the same spot - unless we're going
+ from here straight to NULL, i.e. a call or jump to 0. */
+ gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
+ gdb_assert (nnpc != npc || orig_npc == 0);
+
+ return 1;
}
static void
-sparc_write_pc (CORE_ADDR pc, ptid_t ptid)
+sparc_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
- write_register_pid (tdep->pc_regnum, pc, ptid);
- write_register_pid (tdep->npc_regnum, pc + 4, ptid);
+ regcache_cooked_write_unsigned (regcache, tdep->pc_regnum, pc);
+ regcache_cooked_write_unsigned (regcache, tdep->npc_regnum, pc + 4);
}
\f
/* Unglobalize NAME. */