This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH/v2] Fix PR backtrace/16558: GDB Aarch64 signal frame unwinder issue


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 =



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]