On Tue, Oct 17, 2017 at 03:44:36PM -0400, Dave Anderson wrote:
Oops, I've made small changes, nothing essential but some sort of
clean-ups/readability improvements with deleting incomplete fixes
against "bt -o."
Thanks,
-Takahiro AKASHI
===8<===
From 826147807e2f2e00155b41b8ab97d3083bb0e607 Mon Sep 17 00:00:00 2001
From: AKASHI Takahiro <takahiro.akashi(a)linaro.org>
Date: Thu, 12 Oct 2017 10:46:34 +0900
Subject: [PATCH v2] arm64: backtrace for v4.14
---
arm64.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++-----------------
defs.h | 3 +
task.c | 2 +
3 files changed, 161 insertions(+), 56 deletions(-)
diff --git a/arm64.c b/arm64.c
index 20c5d34..80cb476 100644
--- a/arm64.c
+++ b/arm64.c
@@ -72,6 +72,7 @@ static void arm64_cmd_mach(void);
static void arm64_display_machine_stats(void);
static int arm64_get_smp_cpus(void);
static void arm64_clear_machdep_cache(void);
+static int arm64_on_process_stack(struct bt_info *, ulong);
static int arm64_in_alternate_stack(int, ulong);
static int arm64_on_irq_stack(int, ulong);
static void arm64_set_irq_stack(struct bt_info *);
@@ -611,6 +612,7 @@ arm64_dump_machdep_table(ulong arg)
fprintf(fp, " exp_entry2_end: %lx\n", ms->exp_entry2_end);
fprintf(fp, " panic_task_regs: %lx\n", (ulong)ms->panic_task_regs);
fprintf(fp, " user_eframe_offset: %ld\n", ms->user_eframe_offset);
+ fprintf(fp, " kern_eframe_offset: %ld\n", ms->kern_eframe_offset);
fprintf(fp, " PTE_PROT_NONE: %lx\n", ms->PTE_PROT_NONE);
fprintf(fp, " PTE_FILE: ");
if (ms->PTE_FILE)
@@ -1336,31 +1338,64 @@ arm64_irq_stack_init(void)
req = &request;
struct machine_specific *ms = machdep->machspec;
- if (!symbol_exists("irq_stack") ||
- !(sp = per_cpu_symbol_search("irq_stack")) ||
- !get_symbol_type("irq_stack", NULL, req) ||
- (req->typecode != TYPE_CODE_ARRAY) ||
- (req->target_typecode != TYPE_CODE_INT))
- return;
+ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus
+ * sizeof(ulong)))))
+ error(FATAL, "cannot malloc irq_stack addresses\n");
- if (CRASHDEBUG(1)) {
- fprintf(fp, "irq_stack: \n");
- fprintf(fp, " type: %s\n",
- (req->typecode == TYPE_CODE_ARRAY) ? "TYPE_CODE_ARRAY" :
"other");
- fprintf(fp, " target_typecode: %s\n",
- req->target_typecode == TYPE_CODE_INT ? "TYPE_CODE_INT" :
"other");
- fprintf(fp, " target_length: %ld\n", req->target_length);
- fprintf(fp, " length: %ld\n", req->length);
- }
+ if (symbol_exists("irq_stack") &&
+ (sp = per_cpu_symbol_search("irq_stack")) &&
+ get_symbol_type("irq_stack", NULL, req)) {
+ /* before v4.14 or CONFIG_VMAP_STACK disabled */
+ if (CRASHDEBUG(1)) {
+ fprintf(fp, "irq_stack: \n");
+ fprintf(fp, " type: %s\n",
+ (req->typecode == TYPE_CODE_ARRAY) ?
+ "TYPE_CODE_ARRAY" : "other");
+ fprintf(fp, " target_typecode: %s\n",
+ req->target_typecode == TYPE_CODE_INT ?
+ "TYPE_CODE_INT" : "other");
+ fprintf(fp, " target_length: %ld\n",
+ req->target_length);
+ fprintf(fp, " length: %ld\n", req->length);
+ }
- ms->irq_stack_size = req->length;
- if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
- error(FATAL, "cannot malloc irq_stack addresses\n");
+ ms->irq_stack_size = req->length;
+
+ for (i = 0; i < kt->cpus; i++)
+ ms->irq_stacks[i] = kt->__per_cpu_offset[i] + sp->value;
+
+ machdep->flags |= IRQ_STACKS;
+ } else if (symbol_exists("irq_stack_ptr") &&
+ (sp = per_cpu_symbol_search("irq_stack_ptr")) &&
+ get_symbol_type("irq_stack_ptr", NULL, req)) {
+ /* v4.14 and later with CONFIG_VMAP_STACK enabled */
+ if (CRASHDEBUG(1)) {
+ fprintf(fp, "irq_stack_ptr: \n");
+ fprintf(fp, " type: %x, %s\n",
+ (int)req->typecode,
+ (req->typecode == TYPE_CODE_PTR) ?
+ "TYPE_CODE_PTR" : "other");
+ fprintf(fp, " target_typecode: %x, %s\n",
+ (int)req->target_typecode,
+ req->target_typecode == TYPE_CODE_INT ?
+ "TYPE_CODE_INT" : "other");
+ fprintf(fp, " target_length: %ld\n",
+ req->target_length);
+ fprintf(fp, " length: %ld\n", req->length);
+ }
+
+ ms->irq_stack_size = ARM64_IRQ_STACK_SIZE;
- for (i = 0; i < kt->cpus; i++)
- ms->irq_stacks[i] = kt->__per_cpu_offset[i] + sp->value;
+ for (i = 0; i < kt->cpus; i++) {
+ ulong p;
- machdep->flags |= IRQ_STACKS;
+ p = kt->__per_cpu_offset[i] + sp->value;
+ readmem(p, KVADDR, &(ms->irq_stacks[i]), sizeof(ulong),
+ "IRQ stack pointer", RETURN_ON_ERROR);
+ }
+
+ machdep->flags |= IRQ_STACKS;
+ }
}
/*
@@ -1379,10 +1414,13 @@ arm64_stackframe_init(void)
MEMBER_OFFSET_INIT(elf_prstatus_pr_pid, "elf_prstatus", "pr_pid");
MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg");
- if (MEMBER_EXISTS("pt_regs", "stackframe"))
+ if (MEMBER_EXISTS("pt_regs", "stackframe")) {
machdep->machspec->user_eframe_offset = SIZE(pt_regs);
- else
+ machdep->machspec->kern_eframe_offset = SIZE(pt_regs) - 16;
+ } else {
machdep->machspec->user_eframe_offset = SIZE(pt_regs) + 16;
+ machdep->machspec->kern_eframe_offset = SIZE(pt_regs);
+ }
machdep->machspec->__exception_text_start =
symbol_value("__exception_text_start");
@@ -1472,6 +1510,7 @@ arm64_stackframe_init(void)
#define USER_MODE (2)
#define USER_EFRAME_OFFSET (machdep->machspec->user_eframe_offset)
+#define KERN_EFRAME_OFFSET (machdep->machspec->kern_eframe_offset)
/*
* PSR bits
@@ -1747,14 +1786,23 @@ arm64_display_full_frame(struct bt_info *bt, ulong sp)
ulong words, addr;
char buf[BUFSIZE];
- if (bt->frameptr == sp)
+ if (bt->frameptr >= sp)
return;
- if (!INSTACK(sp, bt) || !INSTACK(bt->frameptr, bt)) {
- if (sp == 0)
- sp = bt->stacktop - USER_EFRAME_OFFSET;
- else
- return;
+ if (INSTACK(bt->frameptr, bt)) {
+ if (INSTACK(sp, bt)) {
+ /* normal case */;
+ } else {
+ if (sp == 0)
+ /* interrupt in user mode */
+ sp = bt->stacktop - USER_EFRAME_OFFSET;
+ else
+ /* interrupt in kernel mode */
+ sp = bt->stacktop;
+ }
+ } else {
+ /* This is a transition case from irq to process stack. */
+ return;
}
words = (sp - bt->frameptr) / sizeof(ulong);
@@ -1860,6 +1908,38 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe
*frame)
if ((frame->fp == 0) && (frame->pc == 0))
return FALSE;
+ if (!(machdep->flags & IRQ_STACKS))
+ return TRUE;
+
+ if (machdep->flags & UNW_4_14) {
+ if ((bt->flags & BT_IRQSTACK) &&
+ !arm64_on_irq_stack(bt->tc->processor, frame->fp)) {
+ if (arm64_on_process_stack(bt, frame->fp)) {
+ arm64_set_process_stack(bt);
+
+ frame->sp = frame->fp - KERN_EFRAME_OFFSET;
+ /*
+ * for switch_stack
+ * fp still points to irq stack
+ */
+ bt->bptr = fp;
+ /*
+ * for display_full_frame
+ * sp points to process stack
+ *
+ * If we want to see pt_regs,
+ * comment out the below.
+ * bt->frameptr = frame->sp;
+ */
+ } else {
+ /* irq -> user */
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
/*
* The kernel's manner of determining the end of the IRQ stack:
*
@@ -1872,29 +1952,27 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe
*frame)
* irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
* orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process
stack)
*/
- if (machdep->flags & IRQ_STACKS) {
- ms = machdep->machspec;
- irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size -
16;
-
- if (frame->sp == irq_stack_ptr) {
- orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8);
- arm64_set_process_stack(bt);
- if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp ==
0))) {
- ptregs = (struct arm64_pt_regs
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))];
- frame->sp = orig_sp;
- frame->pc = ptregs->pc;
- bt->bptr = fp;
- if (CRASHDEBUG(1))
- error(INFO,
- "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n",
- frame->fp, frame->sp, frame->pc);
- } else {
- error(WARNING,
- "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n",
- orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)",
- frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)");
- return FALSE;
- }
+ ms = machdep->machspec;
+ irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size -
16;
+
+ if (frame->sp == irq_stack_ptr) {
+ orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8);
+ arm64_set_process_stack(bt);
+ if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0)))
{
+ ptregs = (struct arm64_pt_regs
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))];
+ frame->sp = orig_sp;
+ frame->pc = ptregs->pc;
+ bt->bptr = fp;
+ if (CRASHDEBUG(1))
+ error(INFO,
+ "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n",
+ frame->fp, frame->sp, frame->pc);
+ } else {
+ error(WARNING,
+ "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n",
+ orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)",
+ frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)");
+ return FALSE;
}
}
@@ -2211,6 +2289,11 @@ arm64_back_trace_cmd(struct bt_info *bt)
FILE *ofp;
if (bt->flags & BT_OPT_BACK_TRACE) {
+ if (machdep->flags & UNW_4_14) {
+ error(WARNING, "\"-o\" is no longer supported for this version of
kernel. Please use bt\n");
+ return;
+ }
+
arm64_back_trace_cmd_v2(bt);
return;
}
@@ -2272,7 +2355,7 @@ arm64_back_trace_cmd(struct bt_info *bt)
goto complete_user;
if (DUMPFILE() && is_task_active(bt->task)) {
- exception_frame = stackframe.fp - SIZE(pt_regs);
+ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET;
if (arm64_is_kernel_exception_frame(bt, exception_frame))
arm64_print_exception_frame(bt, exception_frame,
KERNEL_MODE, ofp);
@@ -2304,11 +2387,12 @@ arm64_back_trace_cmd(struct bt_info *bt)
if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) {
if (!(bt->flags & BT_IRQSTACK) ||
(((stackframe.sp + SIZE(pt_regs)) < bt->stacktop)))
- exception_frame = stackframe.fp - SIZE(pt_regs);
+ exception_frame = stackframe.fp
+ - KERN_EFRAME_OFFSET;
}
if ((bt->flags & BT_IRQSTACK) &&
- !arm64_on_irq_stack(bt->tc->processor, stackframe.sp)) {
+ !arm64_on_irq_stack(bt->tc->processor, stackframe.fp)) {
bt->flags &= ~BT_IRQSTACK;
if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE)
break;
@@ -2669,7 +2753,9 @@ arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe
*frame, FILE *ofp
if (frame->fp == 0)
return USER_MODE;
- arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
+ if (!(machdep->flags & UNW_4_14))
+ arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
+
return KERNEL_MODE;
}
@@ -3362,6 +3448,20 @@ arm64_clear_machdep_cache(void) {
return;
}
+static int
+arm64_on_process_stack(struct bt_info *bt, ulong stkptr)
+{
+ ulong stackbase, stacktop;
+
+ stackbase = GET_STACKBASE(bt->task);
+ stacktop = GET_STACKTOP(bt->task);
+
+ if ((stkptr >= stackbase) && (stkptr < stacktop))
+ return TRUE;
+
+ return FALSE;
+}
+
static int
arm64_on_irq_stack(int cpu, ulong stkptr)
{
diff --git a/defs.h b/defs.h
index 7768895..a694a66 100644
--- a/defs.h
+++ b/defs.h
@@ -3038,6 +3038,7 @@ typedef signed int s32;
#define ARM64_VMEMMAP_END (ARM64_VMEMMAP_VADDR + GIGABYTES(8UL) - 1)
#define ARM64_STACK_SIZE (16384)
+#define ARM64_IRQ_STACK_SIZE ARM64_STACK_SIZE
#define _SECTION_SIZE_BITS 30
#define _MAX_PHYSMEM_BITS 40
@@ -3117,6 +3118,8 @@ struct machine_specific {
ulong kimage_text;
ulong kimage_end;
ulong user_eframe_offset;
+ /* for v4.14 or later */
+ ulong kern_eframe_offset;
};
struct arm64_stackframe {
diff --git a/task.c b/task.c
index 2b12af0..23c2b7b 100644
--- a/task.c
+++ b/task.c
@@ -6750,6 +6750,8 @@ panic_search(void)
fd->keyword_array[0] = FOREACH_BT;
if (machine_type("S390X"))
fd->flags |= FOREACH_o_FLAG;
+ else if (machine_type("ARM64") && (machdep->flags & UNW_4_14))
+ fd->flags |= FOREACH_t_FLAG;
else
fd->flags |= (FOREACH_t_FLAG|FOREACH_o_FLAG);
--
2.14.1