}
/* Copy the value of next pc of sigreturn and rt_sigrturn into PC,
- and return 1. Return 0 if it is not a rt_sigreturn/sigreturn
- syscall. */
+ return 1. In addition, set IS_THUMB depending on whether we
+ will return to ARM or Thumb code. Return 0 if it is not a
+ rt_sigreturn/sigreturn syscall. */
static int
arm_linux_sigreturn_return_addr (struct frame_info *frame,
unsigned long svc_number,
- CORE_ADDR *pc)
+ CORE_ADDR *pc, int *is_thumb)
{
/* Is this a sigreturn or rt_sigreturn syscall? */
if (svc_number == 119 || svc_number == 173)
{
if (get_frame_type (frame) == SIGTRAMP_FRAME)
{
+ ULONGEST t_bit = arm_psr_thumb_bit (frame_unwind_arch (frame));
+ CORE_ADDR cpsr
+ = frame_unwind_register_unsigned (frame, ARM_PS_REGNUM);
+
+ *is_thumb = (cpsr & t_bit) != 0;
*pc = frame_unwind_caller_pc (frame);
return 1;
}
CORE_ADDR return_addr = 0;
int is_thumb = arm_frame_is_thumb (frame);
ULONGEST svc_number = 0;
- int is_sigreturn = 0;
if (is_thumb)
{
svc_number = get_frame_register_unsigned (frame, 7);
+ return_addr = pc + 2;
}
else
{
{
svc_number = get_frame_register_unsigned (frame, 7);
}
+
+ return_addr = pc + 4;
}
- is_sigreturn = arm_linux_sigreturn_return_addr (frame, svc_number,
- &return_addr);
+ arm_linux_sigreturn_return_addr (frame, svc_number, &return_addr, &is_thumb);
- if (is_sigreturn)
- return return_addr;
-
+ /* Addresses for calling Thumb functions have the bit 0 set. */
if (is_thumb)
- {
- return_addr = pc + 2;
- /* Addresses for calling Thumb functions have the bit 0 set. */
- return_addr |= 1;
- }
- else
- {
- return_addr = pc + 4;
- }
+ return_addr |= 1;
return return_addr;
}
if (next_pc > 0xffff0000)
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
- insert_single_step_breakpoint (gdbarch, aspace, next_pc);
+ arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
}
static int
-arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
- struct regcache *regs, struct displaced_step_closure *dsc)
+arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
- CORE_ADDR from = dsc->insn_addr;
CORE_ADDR return_to = 0;
struct frame_info *frame;
- unsigned int svc_number = displaced_read_reg (regs, from, 7);
+ unsigned int svc_number = displaced_read_reg (regs, dsc, 7);
int is_sigreturn = 0;
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying Linux svc insn %.8lx\n",
- (unsigned long) insn);
+ int is_thumb;
frame = get_current_frame ();
is_sigreturn = arm_linux_sigreturn_return_addr(frame, svc_number,
- &return_to);
+ &return_to, &is_thumb);
if (is_sigreturn)
{
struct symtab_and_line sal;
Cleanup: if pc lands in scratch space, pc <- insn_addr + 4
else leave pc alone. */
- dsc->modinsn[0] = insn;
dsc->cleanup = &arm_linux_cleanup_svc;
/* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
Insn: ldr pc, [r14, #4]
Cleanup: r14 <- tmp[0], pc <- tmp[0]. */
- dsc->tmp[0] = displaced_read_reg (regs, from, ARM_LR_REGNUM);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, ARM_LR_REGNUM);
displaced_write_reg (regs, dsc, ARM_LR_REGNUM, (ULONGEST) to + 4,
CANNOT_WRITE_PC);
write_memory_unsigned_integer (to + 8, 4, byte_order, from);