[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