|
|
7ab123 |
commit f2205de0080d999c9b67872c9db471c31b53e378
|
|
|
7ab123 |
Author: Hui Zhu <teawater@gmail.com>
|
|
|
7ab123 |
Date: Tue May 20 13:19:06 2014 +0800
|
|
|
7ab123 |
|
|
|
7ab123 |
Fix issue #15778: GDB Aarch64 signal frame unwinder issue
|
|
|
7ab123 |
|
|
|
7ab123 |
The root cause of this issue is unwinder of "#3 <signal handler called>"
|
|
|
7ab123 |
doesn't supply right values of registers.
|
|
|
7ab123 |
When GDB want to get the previous frame of "#3 <signal handler called>",
|
|
|
7ab123 |
it will call cache init function of unwinder "aarch64_linux_sigframe_init".
|
|
|
7ab123 |
The address or the value of the registers is get from this function.
|
|
|
7ab123 |
So the bug is inside thie function.
|
|
|
7ab123 |
|
|
|
7ab123 |
I check the asm code of "#3 <signal handler called>":
|
|
|
7ab123 |
(gdb) frame 3
|
|
|
7ab123 |
(gdb) p $pc
|
|
|
7ab123 |
$1 = (void (*)()) 0x7f931fa4d0
|
|
|
7ab123 |
(gdb) disassemble $pc, +10
|
|
|
7ab123 |
Dump of assembler code from 0x7f931fa4d0 to 0x7f931fa4da:
|
|
|
7ab123 |
=> 0x0000007f931fa4d0: mov x8, #0x8b // #139
|
|
|
7ab123 |
0x0000007f931fa4d4: svc #0x0
|
|
|
7ab123 |
0x0000007f931fa4d8: nop
|
|
|
7ab123 |
|
|
|
7ab123 |
This is the syscall sys_rt_sigreturn, Linux kernel function "restore_sigframe"
|
|
|
7ab123 |
will set the frame:
|
|
|
7ab123 |
for (i = 0; i < 31; i++)
|
|
|
7ab123 |
__get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
|
|
|
7ab123 |
err);
|
|
|
7ab123 |
__get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
|
|
|
7ab123 |
__get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
|
|
|
7ab123 |
The struct of uc_mcontext is:
|
|
|
7ab123 |
struct sigcontext {
|
|
|
7ab123 |
__u64 fault_address;
|
|
|
7ab123 |
/* AArch64 registers */
|
|
|
7ab123 |
__u64 regs[31];
|
|
|
7ab123 |
__u64 sp;
|
|
|
7ab123 |
__u64 pc;
|
|
|
7ab123 |
__u64 pstate;
|
|
|
7ab123 |
/* 4K reserved for FP/SIMD state and future expansion */
|
|
|
7ab123 |
__u8 __reserved[4096] __attribute__((__aligned__(16)));
|
|
|
7ab123 |
};
|
|
|
7ab123 |
|
|
|
7ab123 |
But in GDB function "aarch64_linux_sigframe_init", the code the get address
|
|
|
7ab123 |
of registers is:
|
|
|
7ab123 |
for (i = 0; i < 31; i++)
|
|
|
7ab123 |
{
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache,
|
|
|
7ab123 |
AARCH64_X0_REGNUM + i,
|
|
|
7ab123 |
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ i * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
}
|
|
|
7ab123 |
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp);
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8);
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8);
|
|
|
7ab123 |
|
|
|
7ab123 |
The code that get pc and sp is not right, so I change the code according
|
|
|
7ab123 |
to Linux kernel code:
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
|
|
|
7ab123 |
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ 31 * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
|
|
|
7ab123 |
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ 32 * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
|
|
|
7ab123 |
The issue was fixed by this change, and I did the regression test. It
|
|
|
7ab123 |
also fixed a lot of other XFAIL and FAIL.
|
|
|
7ab123 |
|
|
|
7ab123 |
2014-05-20 Hui Zhu <hui@codesourcery.com>
|
|
|
7ab123 |
Yao Qi <yao@codesourcery.com>
|
|
|
7ab123 |
|
|
|
7ab123 |
PR backtrace/16558
|
|
|
7ab123 |
* aarch64-linux-tdep.c (aarch64_linux_sigframe_init): Update comments
|
|
|
7ab123 |
and change address of sp and pc.
|
|
|
7ab123 |
|
|
|
7ab123 |
Index: gdb-7.6.1/gdb/aarch64-linux-tdep.c
|
|
|
7ab123 |
===================================================================
|
|
|
7ab123 |
--- gdb-7.6.1.orig/gdb/aarch64-linux-tdep.c
|
|
|
7ab123 |
+++ gdb-7.6.1/gdb/aarch64-linux-tdep.c
|
|
|
7ab123 |
@@ -47,28 +47,30 @@
|
|
|
7ab123 |
|
|
|
7ab123 |
/* Signal frame handling.
|
|
|
7ab123 |
|
|
|
7ab123 |
- +----------+ ^
|
|
|
7ab123 |
- | saved lr | |
|
|
|
7ab123 |
- +->| saved fp |--+
|
|
|
7ab123 |
- | | |
|
|
|
7ab123 |
- | | |
|
|
|
7ab123 |
- | +----------+
|
|
|
7ab123 |
- | | saved lr |
|
|
|
7ab123 |
- +--| saved fp |
|
|
|
7ab123 |
- ^ | |
|
|
|
7ab123 |
- | | |
|
|
|
7ab123 |
- | +----------+
|
|
|
7ab123 |
- ^ | |
|
|
|
7ab123 |
- | | signal |
|
|
|
7ab123 |
- | | |
|
|
|
7ab123 |
- | | saved lr |-->interrupted_function_pc
|
|
|
7ab123 |
- +--| saved fp |
|
|
|
7ab123 |
- | +----------+
|
|
|
7ab123 |
- | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
|
|
|
7ab123 |
- +--| saved fp |<- FP
|
|
|
7ab123 |
- | |
|
|
|
7ab123 |
- | |<- SP
|
|
|
7ab123 |
- +----------+
|
|
|
7ab123 |
+ +------------+ ^
|
|
|
7ab123 |
+ | saved lr | |
|
|
|
7ab123 |
+ +->| saved fp |--+
|
|
|
7ab123 |
+ | | |
|
|
|
7ab123 |
+ | | |
|
|
|
7ab123 |
+ | +------------+
|
|
|
7ab123 |
+ | | saved lr |
|
|
|
7ab123 |
+ +--| saved fp |
|
|
|
7ab123 |
+ ^ | |
|
|
|
7ab123 |
+ | | |
|
|
|
7ab123 |
+ | +------------+
|
|
|
7ab123 |
+ ^ | |
|
|
|
7ab123 |
+ | | signal |
|
|
|
7ab123 |
+ | | | SIGTRAMP_FRAME (struct rt_sigframe)
|
|
|
7ab123 |
+ | | saved regs |
|
|
|
7ab123 |
+ +--| saved sp |--> interrupted_sp
|
|
|
7ab123 |
+ | | saved pc |--> interrupted_pc
|
|
|
7ab123 |
+ | | |
|
|
|
7ab123 |
+ | +------------+
|
|
|
7ab123 |
+ | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
|
|
|
7ab123 |
+ +--| saved fp |<- FP
|
|
|
7ab123 |
+ | | NORMAL_FRAME
|
|
|
7ab123 |
+ | |<- SP
|
|
|
7ab123 |
+ +------------+
|
|
|
7ab123 |
|
|
|
7ab123 |
On signal delivery, the kernel will create a signal handler stack
|
|
|
7ab123 |
frame and setup the return address in LR to point at restorer stub.
|
|
|
7ab123 |
@@ -117,6 +119,8 @@
|
|
|
7ab123 |
d28015a8 movz x8, #0xad
|
|
|
7ab123 |
d4000001 svc #0x0
|
|
|
7ab123 |
|
|
|
7ab123 |
+ This is a system call sys_rt_sigreturn.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
We detect signal frames by snooping the return code for the restorer
|
|
|
7ab123 |
instruction sequence.
|
|
|
7ab123 |
|
|
|
7ab123 |
@@ -140,7 +144,6 @@ aarch64_linux_sigframe_init (const struc
|
|
|
7ab123 |
{
|
|
|
7ab123 |
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
|
|
7ab123 |
CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
|
|
|
7ab123 |
- CORE_ADDR fp = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM);
|
|
|
7ab123 |
CORE_ADDR sigcontext_addr =
|
|
|
7ab123 |
sp
|
|
|
7ab123 |
+ AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
|
|
|
7ab123 |
@@ -154,12 +157,14 @@ aarch64_linux_sigframe_init (const struc
|
|
|
7ab123 |
sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ i * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
}
|
|
|
7ab123 |
+ trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
|
|
|
7ab123 |
+ sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ + 31 * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
+ trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
|
|
|
7ab123 |
+ sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
|
|
|
7ab123 |
+ + 32 * AARCH64_SIGCONTEXT_REG_SIZE);
|
|
|
7ab123 |
|
|
|
7ab123 |
- trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp);
|
|
|
7ab123 |
- trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8);
|
|
|
7ab123 |
- trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8);
|
|
|
7ab123 |
-
|
|
|
7ab123 |
- trad_frame_set_id (this_cache, frame_id_build (fp, func));
|
|
|
7ab123 |
+ trad_frame_set_id (this_cache, frame_id_build (sp, func));
|
|
|
7ab123 |
}
|
|
|
7ab123 |
|
|
|
7ab123 |
static const struct tramp_frame aarch64_linux_rt_sigframe =
|
|
|
7ab123 |
Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.exp
|
|
|
7ab123 |
===================================================================
|
|
|
7ab123 |
--- /dev/null
|
|
|
7ab123 |
+++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.exp
|
|
|
7ab123 |
@@ -0,0 +1,35 @@
|
|
|
7ab123 |
+# Copyright (C) 2014 Free Software Foundation, Inc.
|
|
|
7ab123 |
+#
|
|
|
7ab123 |
+# This program is free software; you can redistribute it and/or modify
|
|
|
7ab123 |
+# it under the terms of the GNU General Public License as published by
|
|
|
7ab123 |
+# the Free Software Foundation; either version 3 of the License, or
|
|
|
7ab123 |
+# (at your option) any later version.
|
|
|
7ab123 |
+#
|
|
|
7ab123 |
+# This program is distributed in the hope that it will be useful,
|
|
|
7ab123 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
7ab123 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
7ab123 |
+# GNU General Public License for more details.
|
|
|
7ab123 |
+#
|
|
|
7ab123 |
+# You should have received a copy of the GNU General Public License
|
|
|
7ab123 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+# Internal testing for RHEL-7.1.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+standard_testfile
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+if { ![istarget "aarch64*"] } {
|
|
|
7ab123 |
+ verbose "Skipping $testfile"
|
|
|
7ab123 |
+ return
|
|
|
7ab123 |
+}
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
|
|
|
7ab123 |
+ return -1
|
|
|
7ab123 |
+}
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+if ![runto_main] {
|
|
|
7ab123 |
+ return -1
|
|
|
7ab123 |
+}
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+gdb_test "continue" "Continuing.\r\n\r\nProgram received signal SIGSEGV.*" "run until SIGSEGV"
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+gdb_test "backtrace" "#$decimal\\s+$hex in pause .*from.*" "backtrace on signal handler"
|
|
|
7ab123 |
Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.c
|
|
|
7ab123 |
===================================================================
|
|
|
7ab123 |
--- /dev/null
|
|
|
7ab123 |
+++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.c
|
|
|
7ab123 |
@@ -0,0 +1,40 @@
|
|
|
7ab123 |
+/* Copyright 2014 Free Software Foundation, Inc.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+ This file is part of GDB.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+ This program is free software; you can redistribute it and/or modify
|
|
|
7ab123 |
+ it under the terms of the GNU General Public License as published by
|
|
|
7ab123 |
+ the Free Software Foundation; either version 3 of the License, or
|
|
|
7ab123 |
+ (at your option) any later version.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+ This program is distributed in the hope that it will be useful,
|
|
|
7ab123 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
7ab123 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
7ab123 |
+ GNU General Public License for more details.
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+ You should have received a copy of the GNU General Public License
|
|
|
7ab123 |
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+/* Internal test for RHEL-7.1. */
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+#include <sys/types.h>
|
|
|
7ab123 |
+#include <signal.h>
|
|
|
7ab123 |
+#include <unistd.h>
|
|
|
7ab123 |
+#include <assert.h>
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+static void
|
|
|
7ab123 |
+handle_alrm(int signo)
|
|
|
7ab123 |
+{
|
|
|
7ab123 |
+ kill (getpid (), SIGSEGV);
|
|
|
7ab123 |
+ assert (0);
|
|
|
7ab123 |
+}
|
|
|
7ab123 |
+
|
|
|
7ab123 |
+int
|
|
|
7ab123 |
+main (int argc, char *argv[])
|
|
|
7ab123 |
+{
|
|
|
7ab123 |
+ signal (SIGALRM, handle_alrm);
|
|
|
7ab123 |
+ alarm (1);
|
|
|
7ab123 |
+ pause ();
|
|
|
7ab123 |
+ assert (0);
|
|
|
7ab123 |
+ return 0;
|
|
|
7ab123 |
+}
|