/* Syscall number for rt_sigreturn. */
#define ARM_RT_SIGRETURN 173
+static CORE_ADDR
+ arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self,
+ CORE_ADDR pc);
+
/* Operation function pointers for get_next_pcs. */
static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
arm_get_next_pcs_read_memory_unsigned_integer,
- arm_get_next_pcs_syscall_next_pc,
+ arm_linux_get_next_pcs_syscall_next_pc,
arm_get_next_pcs_addr_bits_remove,
- arm_get_next_pcs_is_thumb
+ arm_get_next_pcs_is_thumb,
+ arm_linux_get_next_pcs_fixup,
};
static void
}
/* Find the value of the next PC after a sigreturn or rt_sigreturn syscall
- based on current processor state. */
+ based on current processor state. In addition, set IS_THUMB depending
+ on whether we will return to ARM or Thumb code. */
+
static CORE_ADDR
arm_linux_sigreturn_next_pc (struct regcache *regcache,
- unsigned long svc_number)
+ unsigned long svc_number, int *is_thumb)
{
ULONGEST sp;
unsigned long sp_data;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int pc_offset = 0;
int is_sigreturn = 0;
+ CORE_ADDR cpsr;
gdb_assert (svc_number == ARM_SIGRETURN
|| svc_number == ARM_RT_SIGRETURN);
next_pc = read_memory_unsigned_integer (sp + pc_offset, 4, byte_order);
+ /* Set IS_THUMB according the CPSR saved on the stack. */
+ cpsr = read_memory_unsigned_integer (sp + pc_offset + 4, 4, byte_order);
+ *is_thumb = ((cpsr & arm_psr_thumb_bit (gdbarch)) != 0);
+
return next_pc;
}
return svc_number;
}
-/* When the processor is at a syscall instruction, return the PC of the
- next instruction to be executed. */
-
static CORE_ADDR
-arm_linux_syscall_next_pc (struct regcache *regcache)
+arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self,
+ CORE_ADDR pc)
{
- CORE_ADDR pc = regcache_read_pc (regcache);
CORE_ADDR next_pc = 0;
- int is_thumb = arm_is_thumb (regcache);
+ int is_thumb = arm_is_thumb (self->regcache);
ULONGEST svc_number = 0;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = get_regcache_arch (self->regcache);
if (is_thumb)
{
- svc_number = regcache_raw_get_unsigned (regcache, 7);
+ svc_number = regcache_raw_get_unsigned (self->regcache, 7);
next_pc = pc + 2;
}
else
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = get_regcache_arch (self->regcache);
enum bfd_endian byte_order_for_code =
gdbarch_byte_order_for_code (gdbarch);
unsigned long this_instr =
}
else /* EABI. */
{
- svc_number = regcache_raw_get_unsigned (regcache, 7);
+ svc_number = regcache_raw_get_unsigned (self->regcache, 7);
}
next_pc = pc + 4;
}
if (svc_number == ARM_SIGRETURN || svc_number == ARM_RT_SIGRETURN)
- next_pc = arm_linux_sigreturn_next_pc (regcache, svc_number);
+ {
+ /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so
+ update IS_THUMB. */
+ next_pc = arm_linux_sigreturn_next_pc (self->regcache, svc_number,
+ &is_thumb);
+ }
/* Addresses for calling Thumb functions have the bit 0 set. */
if (is_thumb)
1,
regcache);
- next_pcs = arm_get_next_pcs (&next_pcs_ctx, regcache_read_pc (regcache));
+ next_pcs = arm_get_next_pcs (&next_pcs_ctx);
for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
- {
- /* The Linux kernel offers some user-mode helpers in a high page. We can
- not read this page (as of 2.6.23), and even if we could then we
- couldn't set breakpoints in it, and even if we could then the atomic
- operations would fail when interrupted. They are all called as
- functions and return to the address in LR, so step to there
- instead. */
- if (pc > 0xffff0000)
- pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
-
- arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
- }
+ arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
do_cleanups (old_chain);
/* Linux-specific displaced step instruction copying function. Detects when
the program has stepped into a Linux kernel helper routine (which must be
- handled as a special case), falling back to arm_displaced_step_copy_insn()
- if it hasn't. */
+ handled as a special case). */
static struct displaced_step_closure *
arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
set_gdbarch_stap_parse_special_token (gdbarch,
arm_stap_parse_special_token);
- tdep->syscall_next_pc = arm_linux_syscall_next_pc;
-
/* `catch syscall' */
set_xml_syscall_file_name (gdbarch, "syscalls/arm-linux.xml");
set_gdbarch_get_syscall_number (gdbarch, arm_linux_get_syscall_number);