summaryrefslogtreecommitdiff
path: root/gdb/arm-linux-tdep.c
diff options
context:
space:
mode:
authorYao Qi <yao.qi@linaro.org>2016-01-21 07:48:50 +0000
committerYao Qi <yao.qi@linaro.org>2016-01-21 07:48:50 +0000
commitf7a6a40dbc279f0a54bdf947077cbad8ad52564c (patch)
tree372b9e3adff7b6c41aafc720efc250ffb5b8a0f5 /gdb/arm-linux-tdep.c
parent7304afd662c3dfe0a97dd57928e018b2923bba26 (diff)
Detect the arm/thumb mode of code SIGRETURN or RT_SIGRETURN returns to
This patch fixes the following regression introduced by commit d0e59a68 step^M 39 } /* handler */^M 1: x/i $pc^M => 0x8740 <handler+80>: sub sp, r11, #0^M (gdb) step^M ^M Program received signal SIGSEGV, Segmentation fault.^M setitimer () at ../sysdeps/unix/syscall-template.S:81^M 81 ../sysdeps/unix/syscall-template.S: No such file or directory.^M 1: x/i $pc^M => 0xb6eff9c0 <setitimer>: push {r7}^M (gdb) FAIL: gdb.base/sigstep.exp: continue to handler, si+advance in handler, step from handler: leave handler in my test setting, program is compiled in arm mode, but the glibc is built in thumb mode, so when we do 'step' to step over syscall instruction svc for SIGRETURN, GDB should set breakpoint for arm mode in the program, even though the current program in glibc is in thumb mode. Current GDB doesn't consider the case that the mode of program SIGRETURN goes to can be different from current program mode. In fact, GDB has taken care of this arm/thumb mode changes already, see /* Copy the value of next pc of sigreturn and rt_sigrturn into PC, 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, int *is_thumb) but in the commit d0e59a68 > - arm_linux_sigreturn_return_addr (frame, svc_number, &return_addr, &is_thumb); > + if (svc_number == ARM_SIGRETURN || svc_number == ARM_RT_SIGRETURN) > + next_pc = arm_linux_sigreturn_next_pc (regcache, svc_number); the IS_THUMB setting is lost, so it is a regression. gdb: 2016-01-21 Yao Qi <yao.qi@linaro.org> * arm-linux-tdep.c (arm_linux_sigreturn_next_pc): Add parameter is_thumb and set it according to CPSR saved on the stack. (arm_linux_get_next_pcs_syscall_next_pc): Pass is_thumb to arm_linux_sigreturn_next_pc. gdb/gdbserver: 2016-01-21 Yao Qi <yao.qi@linaro.org> * linux-arm-low.c (arm_sigreturn_next_pc): Add parameter is_thumb and set it according to CPSR saved on the stack. (get_next_pcs_syscall_next_pc): Pass is_thumb to arm_sigreturn_next_pc.
Diffstat (limited to 'gdb/arm-linux-tdep.c')
-rw-r--r--gdb/arm-linux-tdep.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 2306bda1a9..f6a831ad31 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -782,10 +782,12 @@ arm_linux_sigreturn_return_addr (struct frame_info *frame,
}
/* 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;
@@ -794,6 +796,7 @@ arm_linux_sigreturn_next_pc (struct regcache *regcache,
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);
@@ -807,6 +810,10 @@ arm_linux_sigreturn_next_pc (struct regcache *regcache,
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;
}
@@ -899,7 +906,12 @@ arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self,
}
if (svc_number == ARM_SIGRETURN || svc_number == ARM_RT_SIGRETURN)
- next_pc = arm_linux_sigreturn_next_pc (self->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)