[PATCH/v2] Fix PR backtrace/16558: GDB Aarch64 signal frame unwinder issue
Hui Zhu
hui_zhu@mentor.com
Wed Mar 5 06:33:00 GMT 2014
New version of patch is same with previous one but updated the comments
to fixed some bugs and make it more clear.
Thanks,
Hui
On 02/12/14 10:15, Hui Zhu wrote:
> 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
> #3 <signal handler called>
> (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 FAILs.
>
> Thanks,
> Hui
>
2014-03-05 Hui Zhu <hui@codesourcery.com>
PR backtrace/16558
* aarch64-linux-tdep.c (aarch64_linux_sigframe_init): Update comments
and change address of sp and pc.
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -53,31 +53,8 @@
/* 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
- +----------+
-
On signal delivery, the kernel will create a signal handler stack
- frame and setup the return address in LR to point at restorer stub.
+ frame in arch/arm64/kernel/signal.c:setup_rt_frame.
The signal stack frame is defined by:
struct rt_sigframe
@@ -123,8 +100,8 @@
d28015a8 movz x8, #0xad
d4000001 svc #0x0
- We detect signal frames by snooping the return code for the restorer
- instruction sequence.
+ This is a system call sys_rt_sigreturn. The kernel will detect signal
+ frame from sp and call arch/arm64/kernel/signal.c:restore_sigframe.
The handler then needs to recover the saved register set from
ucontext.uc_mcontext. */
@@ -146,7 +123,6 @@ aarch64_linux_sigframe_init (const struc
{
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 +136,14 @@ aarch64_linux_sigframe_init (const struc
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 =
More information about the Gdb-patches
mailing list