From: wonderzyp <wonderzyp(a)qq.com>
A segfault issue was observed due to the incorrect irq_stack_size on
ARM64, see the following stack trace:
(gdb) bt
#0 0x00005635ac2b166b in arm64_unwind_frame (frame=0x7ffdaf35cb70, bt=0x7ffdaf35d430)
at arm64.c:2821
#1 arm64_back_trace_cmd (bt=0x7ffdaf35d430) at arm64.c:3306
#2 0x00005635ac27b108 in back_trace (bt=bt@entry=0x7ffdaf35d430) at kernel.c:3239
#3 0x00005635ac2880ae in cmd_bt () at kernel.c:2863
#4 0x00005635ac1f16dc in exec_command () at main.c:893
#5 0x00005635ac1f192a in main_loop () at main.c:840
#6 0x00005635ac50df81 in captured_main (data=<optimized out>) at main.c:1284
#7 gdb_main (args=<optimized out>) at main.c:1313
#8 0x00005635ac50e000 in gdb_main_entry (argc=<optimized out>, argv=<optimized
out>)
at main.c:1338
#9 0x00005635ac1ea2a5 in main (argc=5, argv=0x7ffdaf35dde8) at main.c:721
The issue may be encountered when thread_union symbol not found in vmlinux
due to compiling optimization.
This patch will try the following 2 methods to get the irq_stack_size
when thread_union symbol unavailable:
1. Try getting the value from IKconfig.
2. Try getting the value from kernel code disassembly, to get
THREAD_SHIFT directly from tbnz instruction.
In arch/arm64/kernel/entry.S:
.macro kernel_ventry, el:req, ht:req, regsize:req, label:req
...
add sp, sp, x0
sub x0, sp, x0
tbnz x0, #THREAD_SHIFT, 0f
$ gdb vmlinux
(gdb) disass vectors
Dump of assembler code for function vectors:
...
0xffff800080010804 <+4>: add sp, sp, x0
0xffff800080010808 <+8>: sub x0, sp, x0
0xffff80008001080c <+12>: tbnz w0, #16, 0xffff80008001081c <vectors+28>
Signed-off-by: Yeping.Zheng <yeping.zheng(a)nio.com>
---
Hi Yeping,
Could you please have a test on this patch? I re-drafted the commit
message and cleaned up some code, but the patch is NOT tested, especially
the tbnz part, not sure if it can work as expected. In addition, the
"tbnz" part is a little bit tricky, not sure if @Lianbo likes this
approach or not.
Thanks,
Tao Liu
---
arm64.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 2 deletions(-)
diff --git a/arm64.c b/arm64.c
index b3040d7..363ebab 100644
--- a/arm64.c
+++ b/arm64.c
@@ -93,6 +93,7 @@ static void arm64_calc_VA_BITS(void);
static int arm64_is_uvaddr(ulong, struct task_context *);
static void arm64_calc_KERNELPACMASK(void);
static int arm64_get_vmcoreinfo(unsigned long *vaddr, const char *label, int base);
+static ulong arm64_set_irq_stack_size(void);
struct kernel_range {
unsigned long modules_vaddr, modules_end;
@@ -2223,8 +2224,10 @@ arm64_irq_stack_init(void)
if (MEMBER_EXISTS("thread_union", "stack")) {
if ((sz = MEMBER_SIZE("thread_union", "stack")) > 0)
ms->irq_stack_size = sz;
- } else
- ms->irq_stack_size = ARM64_IRQ_STACK_SIZE;
+ } else {
+ ulong res = arm64_set_irq_stack_size();
+ ms->irq_stack_size = (res > 0) ? res : ARM64_IRQ_STACK_SIZE;
+ }
machdep->flags |= IRQ_STACKS;
@@ -4921,6 +4924,68 @@ static void arm64_calc_KERNELPACMASK(void)
}
}
+static ulong arm64_set_irq_stack_size(void)
+{
+ char *string;
+ int kasan_thread_shift = 0;
+ int min_thread_shift;
+ ulong arm64_page_shift;
+ ulong thread_shift = 0;
+ ulong thread_size;
+
+ char buf1[BUFSIZE];
+ char *pos1, *pos2;
+ int errflag = 0;
+
+ if (kt->ikconfig_flags & IKCONFIG_AVAIL) {
+ if ((get_kernel_config("CONFIG_KASAN_GENERIC", NULL) == IKCONFIG_Y) ||
+ (get_kernel_config("CONFIG_KASAN_SW_TAGS", NULL) == IKCONFIG_Y))
+ kasan_thread_shift = 1;
+ min_thread_shift = 14 + kasan_thread_shift;
+
+ if (get_kernel_config("CONFIG_VMAP_STACK", NULL) == IKCONFIG_Y) {
+ if (get_kernel_config("CONFIG_ARM64_PAGE_SHIFT", &string) ==
IKCONFIG_STR) {
+ arm64_page_shift = atol(string);
+ }
+ if (min_thread_shift < arm64_page_shift){
+ thread_shift = arm64_page_shift;
+ } else {
+ thread_shift = min_thread_shift;
+ }
+ }
+ } else {
+ sprintf(buf1, "x/32i vectors");
+ open_tmpfile();
+ if (!gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR)) {
+ goto out;
+ }
+ rewind(pc->tmpfile);
+ while (fgets(buf1, BUFSIZE, pc->tmpfile)) {
+ if ((pos1 = strstr(buf1, "tbnz"))) {
+ if ((pos2 = strchr(pos1, '#'))) {
+ thread_shift = stol(pos2 + 1,
+ RETURN_ON_ERROR|QUIET,
+ &errflag);
+ if (errflag) {
+ thread_shift = 0;
+ } else if (CRASHDEBUG(1)) {
+ error(INFO, "Detect thread shift"
+ " via tbnz %ld\n", thread_shift);
+ }
+ break;
+ }
+ }
+ }
+out:
+ close_tmpfile();
+ }
+
+ if (!thread_shift)
+ return 0;
+ else
+ return ((1UL) << thread_shift);
+}
+
#endif /* ARM64 */
--
2.40.1