Fix issue #15778: GDB Aarch64 signal frame unwinder issue
The root cause of this issue is unwinder of "#3 <signal handler called>" doesn't supply right values of registers. When GDB want to get the previous frame of "#3 <signal handler called>", it will call cache init function of unwinder "aarch64_linux_sigframe_init". The address or the value of the registers is get from this function. So the bug is inside thie function. I check the asm code of "#3 <signal handler called>": (gdb) frame 3 (gdb) p $pc $1 = (void (*)()) 0x7f931fa4d0 (gdb) disassemble $pc, +10 Dump of assembler code from 0x7f931fa4d0 to 0x7f931fa4da: => 0x0000007f931fa4d0: mov x8, #0x8b // #139 0x0000007f931fa4d4: svc #0x0 0x0000007f931fa4d8: nop This is the syscall sys_rt_sigreturn, Linux kernel function "restore_sigframe" will set the frame: for (i = 0; i < 31; i++) __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], err); __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); The struct of uc_mcontext is: struct sigcontext { __u64 fault_address; /* AArch64 registers */ __u64 regs[31]; __u64 sp; __u64 pc; __u64 pstate; /* 4K reserved for FP/SIMD state and future expansion */ __u8 __reserved[4096] __attribute__((__aligned__(16))); }; But in GDB function "aarch64_linux_sigframe_init", the code the get address of registers is: for (i = 0; i < 31; i++) { trad_frame_set_reg_addr (this_cache, AARCH64_X0_REGNUM + i, sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + i * AARCH64_SIGCONTEXT_REG_SIZE); } trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp); trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8); trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8); The code that get pc and sp is not right, so I change the code according to Linux kernel code: trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM, sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + 31 * AARCH64_SIGCONTEXT_REG_SIZE); trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + 32 * AARCH64_SIGCONTEXT_REG_SIZE); The issue was fixed by this change, and I did the regression test. It also fixed a lot of other XFAIL and FAIL. 2014-05-20 Hui Zhu <hui@codesourcery.com> Yao Qi <yao@codesourcery.com> PR backtrace/16558 * aarch64-linux-tdep.c (aarch64_linux_sigframe_init): Update comments and change address of sp and pc.
This commit is contained in:
parent
cdf2a8b762
commit
f2205de008
2 changed files with 40 additions and 28 deletions
|
@ -1,3 +1,10 @@
|
|||
2014-05-20 Hui Zhu <hui@codesourcery.com>
|
||||
Yao Qi <yao@codesourcery.com>
|
||||
|
||||
PR backtrace/16558
|
||||
* aarch64-linux-tdep.c (aarch64_linux_sigframe_init): Update comments
|
||||
and change address of sp and pc.
|
||||
|
||||
2014-05-19 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdbtypes.c (rank_function): Use XNEWVEC.
|
||||
|
|
|
@ -53,28 +53,30 @@
|
|||
|
||||
/* Signal frame handling.
|
||||
|
||||
+----------+ ^
|
||||
| saved lr | |
|
||||
+->| saved fp |--+
|
||||
| | |
|
||||
| | |
|
||||
| +----------+
|
||||
| | saved lr |
|
||||
+--| saved fp |
|
||||
^ | |
|
||||
| | |
|
||||
| +----------+
|
||||
^ | |
|
||||
| | signal |
|
||||
| | |
|
||||
| | saved lr |-->interrupted_function_pc
|
||||
+--| saved fp |
|
||||
| +----------+
|
||||
| | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
|
||||
+--| saved fp |<- FP
|
||||
| |
|
||||
| |<- SP
|
||||
+----------+
|
||||
+------------+ ^
|
||||
| saved lr | |
|
||||
+->| saved fp |--+
|
||||
| | |
|
||||
| | |
|
||||
| +------------+
|
||||
| | saved lr |
|
||||
+--| saved fp |
|
||||
^ | |
|
||||
| | |
|
||||
| +------------+
|
||||
^ | |
|
||||
| | signal |
|
||||
| | | SIGTRAMP_FRAME (struct rt_sigframe)
|
||||
| | saved regs |
|
||||
+--| saved sp |--> interrupted_sp
|
||||
| | saved pc |--> interrupted_pc
|
||||
| | |
|
||||
| +------------+
|
||||
| | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
|
||||
+--| saved fp |<- FP
|
||||
| | NORMAL_FRAME
|
||||
| |<- SP
|
||||
+------------+
|
||||
|
||||
On signal delivery, the kernel will create a signal handler stack
|
||||
frame and setup the return address in LR to point at restorer stub.
|
||||
|
@ -123,6 +125,8 @@
|
|||
d28015a8 movz x8, #0xad
|
||||
d4000001 svc #0x0
|
||||
|
||||
This is a system call sys_rt_sigreturn.
|
||||
|
||||
We detect signal frames by snooping the return code for the restorer
|
||||
instruction sequence.
|
||||
|
||||
|
@ -146,7 +150,6 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
|
|||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||
CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
|
||||
CORE_ADDR fp = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM);
|
||||
CORE_ADDR sigcontext_addr =
|
||||
sp
|
||||
+ AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
|
||||
|
@ -160,12 +163,14 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
|
|||
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
||||
+ i * AARCH64_SIGCONTEXT_REG_SIZE);
|
||||
}
|
||||
trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
|
||||
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
||||
+ 31 * AARCH64_SIGCONTEXT_REG_SIZE);
|
||||
trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
|
||||
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
||||
+ 32 * AARCH64_SIGCONTEXT_REG_SIZE);
|
||||
|
||||
trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp);
|
||||
trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8);
|
||||
trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8);
|
||||
|
||||
trad_frame_set_id (this_cache, frame_id_build (fp, func));
|
||||
trad_frame_set_id (this_cache, frame_id_build (sp, func));
|
||||
}
|
||||
|
||||
static const struct tramp_frame aarch64_linux_rt_sigframe =
|
||||
|
|
Loading…
Reference in a new issue