Skip to content

Commit

Permalink
arm64: fix backtraces of KASAN kernel dumpfile truncated
Browse files Browse the repository at this point in the history
We met "bt" command on KASAN kernel vmcore display truncated backtraces
like this:

  crash> bt
  PID: 4131   TASK: ffff8001521df000  CPU: 3   COMMAND: "bash"
   #0 [ffff2000224b0cb0] machine_kexec_prepare at ffff2000200bff4c

After digging the root cause, it turns out that arm64_in_kdump_text()
found wrong bt->bptr at "machine_kexec" branch.

Disassemble machine_kexec() of KASAN vmlinux (gcc 7.3.0):

  crash> dis -x machine_kexec
  0xffff2000200bff50 <machine_kexec>:     stp     x29, x30, [sp,#-208]!
  0xffff2000200bff54 <machine_kexec+0x4>: mov     x29, sp
  0xffff2000200bff58 <machine_kexec+0x8>: stp     x19, x20, [sp,#16]
  0xffff2000200bff5c <machine_kexec+0xc>: str     x24, [sp,#56]
  0xffff2000200bff60 <machine_kexec+0x10>:        str     x26, [sp,#72]
  0xffff2000200bff64 <machine_kexec+0x14>:        mov     x2, #0x8ab3
  0xffff2000200bff68 <machine_kexec+0x18>:        add     x1, x29, #0x70
  0xffff2000200bff6c <machine_kexec+0x1c>:        lsr     x1, x1, #3
  0xffff2000200bff70 <machine_kexec+0x20>:        movk    x2, #0x41b5, lsl #16
  0xffff2000200bff74 <machine_kexec+0x24>:        mov     x19, #0x200000000000
  0xffff2000200bff78 <machine_kexec+0x28>:        adrp    x3, 0xffff2000224b0000
  0xffff2000200bff7c <machine_kexec+0x2c>:        movk    x19, #0xdfff, lsl #48
  0xffff2000200bff80 <machine_kexec+0x30>:        add     x3, x3, #0xcb0
  0xffff2000200bff84 <machine_kexec+0x34>:        add     x4, x1, x19
  0xffff2000200bff88 <machine_kexec+0x38>:        stp     x2, x3, [x29,#112]
  0xffff2000200bff8c <machine_kexec+0x3c>:        adrp    x2, 0xffff2000200bf000 <swsusp_arch_resume+0x1e8>
  0xffff2000200bff90 <machine_kexec+0x40>:        add     x2, x2, #0xf50
  0xffff2000200bff94 <machine_kexec+0x44>:        str     x2, [x29,#128]
  0xffff2000200bff98 <machine_kexec+0x48>:        mov     w2, #0xf1f1f1f1
  0xffff2000200bff9c <machine_kexec+0x4c>:        str     w2, [x1,x19]
  0xffff2000200bffa0 <machine_kexec+0x50>:        mov     w2, #0xf200
  0xffff2000200bffa4 <machine_kexec+0x54>:        mov     w1, #0xf3f3f3f3
  0xffff2000200bffa8 <machine_kexec+0x58>:        movk    w2, #0xf2f2, lsl #16
  0xffff2000200bffac <machine_kexec+0x5c>:        stp     w2, w1, [x4,#4]

We notice that:
1. machine_kexec() start address is 0xffff2000200bff50
2. the instruction at machine_kexec+0x44 stores the same value
   0xffff2000200bff50 (comes from 0xffff2000200bf000 + 0xf50)
   into stack postion [x29,#128].

When arm64_in_kdump_text() searches for LR from stack, it met
0xffff2000200bff50 firstly, so got wrong bt->bptr.

We know that the real LR is always greater than the start address
of a function, so let's fix it by changing the search conditon to
(*ptr > xxx_start) && (*ptr < xxx_end).

Signed-off-by: Ding Hui <[email protected]>
  • Loading branch information
cdkey authored and k-hagio committed Dec 9, 2022
1 parent 9f12569 commit 5f27639
Showing 1 changed file with 9 additions and 9 deletions.
18 changes: 9 additions & 9 deletions arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -3479,7 +3479,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
ms = machdep->machspec;
for (ptr = start - 8; ptr >= base; ptr--) {
if (bt->flags & BT_OPT_BACK_TRACE) {
if ((*ptr >= ms->crash_kexec_start) &&
if ((*ptr > ms->crash_kexec_start) &&
(*ptr < ms->crash_kexec_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
Expand All @@ -3488,7 +3488,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
if ((*ptr >= ms->crash_save_cpu_start) &&
if ((*ptr > ms->crash_save_cpu_start) &&
(*ptr < ms->crash_save_cpu_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
Expand All @@ -3498,14 +3498,14 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
return TRUE;
}
} else {
if ((*ptr >= ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
if ((*ptr > ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
bt->bptr = ((ulong)ptr - (ulong)base)
+ task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (machine_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
/*
* Stash the first crash_kexec frame in case the machine_kexec
* frame is not found.
Expand All @@ -3519,7 +3519,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
}
continue;
}
if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
bt->bptr = ((ulong)ptr - (ulong)base)
+ task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
Expand Down Expand Up @@ -3566,7 +3566,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)

for (ptr = start - 8; ptr >= base; ptr--) {
if (bt->flags & BT_OPT_BACK_TRACE) {
if ((*ptr >= ms->crash_kexec_start) &&
if ((*ptr > ms->crash_kexec_start) &&
(*ptr < ms->crash_kexec_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
Expand All @@ -3576,7 +3576,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
FREEBUF(stackbuf);
return TRUE;
}
if ((*ptr >= ms->crash_save_cpu_start) &&
if ((*ptr > ms->crash_save_cpu_start) &&
(*ptr < ms->crash_save_cpu_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
Expand All @@ -3587,15 +3587,15 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
return TRUE;
}
} else {
if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n",
bt->bptr, *ptr);
FREEBUF(stackbuf);
return TRUE;
}
if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n",
Expand Down

0 comments on commit 5f27639

Please sign in to comment.