commit a38e3ec4cb2692205d3af7483192077b1acfb199
Author: Dave Anderson <anderson@redhat.com>
Date: Fri Feb 9 14:58:34 2018 -0500
Fix for the ARM64 "bt" command running against Linux 4.14 and
later kernels. Without the patch, the backtraces of the active
tasks in a kdump-generated dumpfile are truncated. Without the
patch, the panic task will just show the "crash_kexec" frame
and the kernel-entry user-space exception frame; the non-panic
tasks will show their backtraces starting from the stackframe
addresses captured in the per-cpu NT_PRSTATUS notes, and will
not display the exception frame generated by the NMI callback,
nor any stackframes on the IRQ stack.
(anderson@redhat.com)
--- crash-7.2.0/defs.h.orig
+++ crash-7.2.0/defs.h
@@ -3137,6 +3137,8 @@ struct machine_specific {
ulong user_eframe_offset;
/* for v4.14 or later */
ulong kern_eframe_offset;
+ ulong machine_kexec_start;
+ ulong machine_kexec_end;
};
struct arm64_stackframe {
--- crash-7.2.0/arm64.c.orig
+++ crash-7.2.0/arm64.c
@@ -1,8 +1,8 @@
/*
* arm64.c - core analysis suite
*
- * Copyright (C) 2012-2017 David Anderson
- * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2012-2018 David Anderson
+ * Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -633,6 +633,8 @@ arm64_dump_machdep_table(ulong arg)
fprintf(fp, "%lx\n", ms->__SWP_OFFSET_MASK);
else
fprintf(fp, "(unused)\n");
+ fprintf(fp, " machine_kexec_start: %lx\n", ms->machine_kexec_start);
+ fprintf(fp, " machine_kexec_end: %lx\n", ms->machine_kexec_end);
fprintf(fp, " crash_kexec_start: %lx\n", ms->crash_kexec_start);
fprintf(fp, " crash_kexec_end: %lx\n", ms->crash_kexec_end);
fprintf(fp, " crash_save_cpu_start: %lx\n", ms->crash_save_cpu_start);
@@ -1336,7 +1338,7 @@ arm64_irq_stack_init(void)
struct syment *sp;
struct gnu_request request, *req;
struct machine_specific *ms = machdep->machspec;
- ulong p;
+ ulong p, sz;
req = &request;
if (symbol_exists("irq_stack") &&
@@ -1384,7 +1386,26 @@ arm64_irq_stack_init(void)
if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
error(FATAL, "cannot malloc irq_stack addresses\n");
- ms->irq_stack_size = ARM64_IRQ_STACK_SIZE;
+
+ /*
+ * Determining the IRQ_STACK_SIZE is tricky, but for now
+ * 4.14 kernel has:
+ *
+ * #define IRQ_STACK_SIZE THREAD_SIZE
+ *
+ * and finding a solid usage of THREAD_SIZE is hard, but:
+ *
+ * union thread_union {
+ * ...
+ * unsigned long stack[THREAD_SIZE/sizeof(long)];
+ * };
+ */
+ 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;
+
machdep->flags |= IRQ_STACKS;
for (i = 0; i < kt->cpus; i++) {
@@ -1404,7 +1425,7 @@ arm64_stackframe_init(void)
long task_struct_thread;
long thread_struct_cpu_context;
long context_sp, context_pc, context_fp;
- struct syment *sp1, *sp1n, *sp2, *sp2n;
+ struct syment *sp1, *sp1n, *sp2, *sp2n, *sp3, *sp3n;
STRUCT_SIZE_INIT(note_buf, "note_buf_t");
STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus");
@@ -1441,11 +1462,15 @@ arm64_stackframe_init(void)
if ((sp1 = kernel_symbol_search("crash_kexec")) &&
(sp1n = next_symbol(NULL, sp1)) &&
(sp2 = kernel_symbol_search("crash_save_cpu")) &&
- (sp2n = next_symbol(NULL, sp2))) {
+ (sp2n = next_symbol(NULL, sp2)) &&
+ (sp3 = kernel_symbol_search("machine_kexec")) &&
+ (sp3n = next_symbol(NULL, sp3))) {
machdep->machspec->crash_kexec_start = sp1->value;
machdep->machspec->crash_kexec_end = sp1n->value;
machdep->machspec->crash_save_cpu_start = sp2->value;
machdep->machspec->crash_save_cpu_end = sp2n->value;
+ machdep->machspec->machine_kexec_start = sp3->value;
+ machdep->machspec->machine_kexec_end = sp3n->value;
machdep->flags |= KDUMP_ENABLED;
}
@@ -2592,6 +2617,7 @@ arm64_in_kdump_text(struct bt_info *bt,
{
ulong *ptr, *start, *base;
struct machine_specific *ms;
+ ulong crash_kexec_frame;
if (!(machdep->flags & KDUMP_ENABLED))
return FALSE;
@@ -2606,6 +2632,7 @@ arm64_in_kdump_text(struct bt_info *bt,
start = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))];
}
+ crash_kexec_frame = 0;
ms = machdep->machspec;
for (ptr = start - 8; ptr >= base; ptr--) {
if (bt->flags & BT_OPT_BACK_TRACE) {
@@ -2628,13 +2655,27 @@ arm64_in_kdump_text(struct bt_info *bt,
return TRUE;
}
} else {
- if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_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 (crash_kexec)\n", bt->bptr, *ptr);
+ fprintf(fp, "%lx: %lx (machine_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
+ 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.
+ */
+ if (!crash_kexec_frame) {
+ crash_kexec_frame = ((ulong)ptr - (ulong)base)
+ + task_to_stackbase(bt->tc->task);
+ if (CRASHDEBUG(1))
+ fprintf(fp, "%lx: %lx (crash_kexec)\n",
+ bt->bptr, *ptr);
+ }
+ continue;
+ }
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);
@@ -2645,6 +2686,11 @@ arm64_in_kdump_text(struct bt_info *bt,
}
}
+ if (crash_kexec_frame) {
+ bt->bptr = crash_kexec_frame;
+ return TRUE;
+ }
+
return FALSE;
}