Signed-off-by: AKASHI Takahiro <takahiro.akashi(a)linaro.org>
---
arm64.c | 504 +++++++++++++++++++++++++++++++++++++++++++---------------------
defs.h | 6 +
2 files changed, 344 insertions(+), 166 deletions(-)
diff --git a/arm64.c b/arm64.c
index 06676d1..4f85772 100644
--- a/arm64.c
+++ b/arm64.c
@@ -42,18 +42,18 @@ static void arm64_irq_stack_init(void);
static void arm64_stackframe_init(void);
static int arm64_eframe_search(struct bt_info *);
static int arm64_is_kernel_exception_frame(struct bt_info *, ulong);
-static int arm64_in_exception_text(ulong);
+static int arm64_in_exp_entry(ulong);
static void arm64_back_trace_cmd(struct bt_info *);
static void arm64_print_text_symbols(struct bt_info *, struct arm64_stackframe *, FILE
*);
static int arm64_print_stackframe_entry(struct bt_info *, int, struct arm64_stackframe *,
FILE *);
-static void arm64_display_full_frame(struct bt_info *, ulong);
-static int arm64_unwind_frame(struct bt_info *, struct arm64_stackframe *);
+static void arm64_display_full_frame(struct bt_info *, struct arm64_stackframe *, struct
arm64_stackframe *);
+static int arm64_unwind_frame(struct bt_info *, struct arm64_stackframe *, FILE *);
static int arm64_get_dumpfile_stackframe(struct bt_info *, struct arm64_stackframe *);
static int arm64_in_kdump_text(struct bt_info *, struct arm64_stackframe *);
static int arm64_in_kdump_text_on_irq_stack(struct bt_info *);
-static int arm64_switch_stack(struct bt_info *, struct arm64_stackframe *, FILE *);
static int arm64_get_stackframe(struct bt_info *, struct arm64_stackframe *);
static void arm64_get_stack_frame(struct bt_info *, ulong *, ulong *);
+static void arm64_gen_hidden_frame(struct bt_info *bt, ulong, struct arm64_stackframe
*);
static void arm64_print_exception_frame(struct bt_info *, ulong, int, FILE *);
static void arm64_do_bt_reference_check(struct bt_info *, ulong, char *);
static int arm64_translate_pte(ulong, void *, ulonglong);
@@ -580,6 +580,10 @@ arm64_dump_machdep_table(ulong arg)
fprintf(fp, " __exception_text_end: %lx\n", ms->__exception_text_end);
fprintf(fp, " __irqentry_text_start: %lx\n", ms->__irqentry_text_start);
fprintf(fp, " __irqentry_text_end: %lx\n", ms->__irqentry_text_end);
+ fprintf(fp, " exp_entry1_start: %lx\n", ms->exp_entry1_start);
+ fprintf(fp, " exp_entry1_end: %lx\n", ms->exp_entry1_end);
+ fprintf(fp, " exp_entry2_start: %lx\n", ms->exp_entry2_start);
+ 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, " PTE_PROT_NONE: %lx\n", ms->PTE_PROT_NONE);
fprintf(fp, " PTE_FILE: ");
@@ -1286,6 +1290,15 @@ arm64_stackframe_init(void)
machdep->machspec->__irqentry_text_start = sp1->value;
machdep->machspec->__irqentry_text_end = sp2->value;
}
+ if ((sp1 = kernel_symbol_search("vectors")) &&
+ (sp1n = kernel_symbol_search("cpu_switch_to")) &&
+ (sp2 = kernel_symbol_search("ret_fast_syscall")) &&
+ (sp2n = kernel_symbol_search("sys_rt_sigreturn_wrapper"))) {
+ machdep->machspec->exp_entry1_start = sp1->value;
+ machdep->machspec->exp_entry1_end = sp1n->value;
+ machdep->machspec->exp_entry2_start = sp2->value;
+ machdep->machspec->exp_entry2_end = sp2n->value;
+ }
if ((sp1 = kernel_symbol_search("crash_kexec")) &&
(sp1n = next_symbol(NULL, sp1)) &&
@@ -1472,25 +1485,20 @@ arm64_eframe_search(struct bt_info *bt)
}
static int
-arm64_in_exception_text(ulong ptr)
+arm64_in_exp_entry(ulong addr)
{
- struct machine_specific *ms = machdep->machspec;
+ struct machine_specific *ms;
- if ((ptr >= ms->__exception_text_start) &&
- (ptr < ms->__exception_text_end))
+ ms = machdep->machspec;
+ if ((ms->exp_entry1_start <= addr) && (addr < ms->exp_entry1_end))
return TRUE;
-
- if (ms->__irqentry_text_start && ms->__irqentry_text_end &&
- ((ptr >= ms->__irqentry_text_start) &&
- (ptr < ms->__irqentry_text_end)))
+ if ((ms->exp_entry2_start <= addr) && (addr < ms->exp_entry2_end))
return TRUE;
-
return FALSE;
}
#define BACKTRACE_CONTINUE (1)
#define BACKTRACE_COMPLETE_KERNEL (2)
-#define BACKTRACE_COMPLETE_USER (3)
static int
arm64_print_stackframe_entry(struct bt_info *bt, int level, struct arm64_stackframe
*frame, FILE *ofp)
@@ -1511,11 +1519,6 @@ arm64_print_stackframe_entry(struct bt_info *bt, int level, struct
arm64_stackfr
value_to_symstr(frame->pc, buf, bt->radix);
}
- if ((bt->flags & BT_FULL) && level) {
- arm64_display_full_frame(bt, frame->fp);
- bt->frameptr = frame->fp;
- }
-
fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " :
"", level,
frame->fp ? frame->fp : bt->stacktop - USER_EFRAME_OFFSET,
name_plus_offset ? name_plus_offset : name, frame->pc);
@@ -1534,7 +1537,8 @@ arm64_print_stackframe_entry(struct bt_info *bt, int level, struct
arm64_stackfr
fprintf(ofp, " %s\n", buf);
}
- if (STREQ(name, "start_kernel") || STREQ(name,
"secondary_start_kernel") ||
+ if (STREQ(name, "start_kernel") ||
+ STREQ(name, "secondary_start_kernel") ||
STREQ(name, "kthread") || STREQ(name, "kthreadd"))
return BACKTRACE_COMPLETE_KERNEL;
@@ -1542,46 +1546,169 @@ arm64_print_stackframe_entry(struct bt_info *bt, int level,
struct arm64_stackfr
}
static void
-arm64_display_full_frame(struct bt_info *bt, ulong sp)
+arm64_display_full_frame(struct bt_info *bt, struct arm64_stackframe *cur,
+ struct arm64_stackframe *next)
{
+ struct machine_specific *ms;
+ ulong next_fp, stackbase;
+ char *stackbuf;
int i, u_idx;
ulong *up;
ulong words, addr;
char buf[BUFSIZE];
- if (bt->frameptr == sp)
- return;
+ stackbase = bt->stackbase;
+ stackbuf = bt->stackbuf;
+ ms = machdep->machspec;
- if (!INSTACK(sp, bt) || !INSTACK(bt->frameptr, bt)) {
- if (sp == 0)
- sp = bt->stacktop - USER_EFRAME_OFFSET;
- else
- return;
- }
+ /* Calc next fp for dump */
+ if (next->fp == 0)
+ /* last stackframe on kernel tack */
+ next_fp = bt->stacktop - 0x10;
+ else if (!INSTACK(cur->sp, bt)) {
+ /* We have just switched over stacks */
+ next_fp = ms->irq_stacks[bt->tc->processor]
+ + ms->irq_stack_size - 0x10;
- words = (sp - bt->frameptr) / sizeof(ulong);
+ /*
+ * We are already buffering a process stack.
+ * So use an old buffer for IRQ stack.
+ */
+ stackbase = ms->irq_stacks[bt->tc->processor];
+ stackbuf = ms->irq_stackbuf;
+ } else
+ next_fp = next->fp;
- addr = bt->frameptr;
- u_idx = (bt->frameptr - bt->stackbase)/sizeof(ulong);
+ if (CRASHDEBUG(1))
+ fprintf(fp, " frame <%016lx:%016lx>\n", cur->fp, next_fp);
+
+ /* Check here because we want to see a debug message above. */
+ if (!(bt->flags & BT_FULL))
+ return;
+
+ /* Dump */
+ words = (next_fp - cur->fp) / sizeof(ulong);
+ addr = cur->fp;
+ u_idx = (cur->fp - stackbase)/sizeof(ulong);
for (i = 0; i < words; i++, u_idx++) {
if (!(i & 1))
fprintf(fp, "%s %lx: ", i ? "\n" : "", addr);
- up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]);
+ up = (ulong *)(&stackbuf[u_idx*sizeof(ulong)]);
fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));
addr += sizeof(ulong);
}
fprintf(fp, "\n");
+
+ if (stackbuf == ms->irq_stackbuf)
+ FREEBUF(stackbuf);
}
-static int
-arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
+/*
+ * (1)Normal frame:
+ * +------+
+ * | pfp |
+ * | cpc |
+ * psp + +
+ * | |
+ * | |
+ * pfp +------+ <--- :prev stackframe = <pfp, psp, ppc>
+ * | cfp |
+ * | npc |
+ * csp + +
+ * | |
+ * | |
+ * cfp +------+ <--- :curr stackframe = <cfp, csp, cpc>
+ * | nfp | | cfp = *pfp
+ * | Npc | | csp = pfp + 0x10
+ * nsp + + real stackframe
+ * | | | at cpc
+ * | | |
+ * nfp +------+ <--- :next stackframe = <nfp, nsp, npc>
+ * | |
+ *
+ * (2)Exception:
+ * +------+
+ * | pfp |
+ * | cpc |
+ * psp + +
+ * | |
+ * | |
+ * pfp +------+ <--- :prev stackframe = <pfp, psp, ppc>
+ * | cfp |
+ * | npc |
+ * csp + +
+ * | |
+ * | |
+ * cfp +------+ <--- :stackframe = <cfp, csp, cpc>
+ * | nfp |
+ * | epc |
+ * + +
+ * | |
+ * | | calced dummy
+ * esp +------+ <--- :exp stackframe = <---, esp, epc>
+ * | | esp = nsp - sizeof(pt_regs)
+ * | |
+ * | Npc |
+ * | nfp |
+ * | nsp |
+ * | npc |
+ * nsp + +
+ * | | calced missing
+ * nfp +------+ <--- :task stackframe = <nfp, nsp, npc>
+ * | Nfp |
+ * | NNpc |
+ * Nsp + +
+ * | |
+ * Nfp +------+ <--- :task stackframe = <Nfp, Nsp, Npc>
+ * | NNfp |
+ *
+ * (3)At interrupt:
+ * +------+
+ * | pfp |
+ * | cpc |
+ * psp + +
+ * | |
+ * | |
+ * pfp +------+ <--- :prev stackframe = <pfp, psp, ppc>
+ * | cfp |
+ * | epc |
+ * csp + +
+ * | |
+ * | | calced dummy
+ * cfp +------+ <--- :irq stackframe = <cfp, csp, epc>
+ * | nfp | | if (cfp == IRQ_STACK_PTR)
+ * | esp | V
+ * top +------+ <---, esp, epc>
+ * IRQ stack
+ *
+ * calced dummy
+ * esp +------+ <--- :exp stackframe = <---, esp, epc>
+ * | | esp = nsp - sizeof(pt_regs)
+ * | |
+ * | Npc |
+ * | nfp |
+ * | nsp |
+ * | npc | calced missing
+ * nfp +------+ <--- :task stackframe = <nfp, nsp, npc>
+ * | Nfp |
+ * | NNpc |
+ * Nsp + +
+ * | |
+ * Nfp +------+ <--- :task stackframe = <Nfp, Nsp, Npc>
+ * | NNfp |
+ */
+
+static struct arm64_stackframe ext_frame;
+
+static int
+arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame,
+ FILE *ofp)
{
unsigned long high, low, fp;
unsigned long stack_mask;
- unsigned long irq_stack_ptr, orig_sp;
- struct arm64_pt_regs *ptregs;
+ unsigned long irq_stack_ptr;
struct machine_specific *ms;
stack_mask = (unsigned long)(ARM64_STACK_SIZE) - 1;
@@ -1593,54 +1720,115 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe
*frame)
if (fp < low || fp > high || fp & 0xf)
return FALSE;
- frame->sp = fp + 0x10;
- frame->fp = GET_STACK_ULONG(fp);
+ if (CRASHDEBUG(1))
+ fprintf(ofp, " cur fp:%016lx sp:%016lx pc:%016lx\n",
+ frame->fp, frame->sp, frame->pc);
+
+ if (ext_frame.pc) {
+ /*
+ * Previous frame was a dummy for exception entry.
+ * So insert a hidden (real) stackframe.
+ */
+ frame->fp = ext_frame.fp;
+ frame->sp = ext_frame.sp;
+ frame->pc = ext_frame.pc;
+
+ ext_frame.pc = 0; /* back to normal unwinding */
+
+ goto unwind_done;
+ }
+
frame->pc = GET_STACK_ULONG(fp + 8);
+ if (!arm64_in_exp_entry(frame->pc)) {
+ /* Normal stack frame */
- /*
- * The kernel's manner of determining the end of the IRQ stack:
- *
- * #define THREAD_SIZE 16384
- * #define THREAD_START_SP (THREAD_SIZE - 16)
- * #define IRQ_STACK_START_SP THREAD_START_SP
- * #define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) +
IRQ_STACK_START_SP)
- * #define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
- *
- * 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);
+ frame->sp = fp + 0x10;
+ frame->fp = GET_STACK_ULONG(fp);
+ } else {
+ /*
+ * We are in exception entry code, and so need to
+ * - fake a dummy frame for exception frame, and
+ * - complement a stackframe hidden by exception
+ */
+
+ ext_frame.fp = GET_STACK_ULONG(fp);
+ if (ext_frame.fp == 0) {
+ /*
+ * Either on process stack or on IRQ stack,
+ * the next frame is the last one on process stack.
+ */
+
+ frame->sp = bt->stacktop
+ - sizeof(struct arm64_pt_regs) - 0x10;
+ frame->fp = frame->sp;
+ } else if (!arm64_on_irq_stack(bt->tc->processor, frame->sp)) {
+ /*
+ * We are on process stack. Just fake a dummy frame
+ */
+
+ if (!arm64_on_irq_stack(bt->tc->processor, fp))
+ /*
+ * Very rare corner case:
+ * We have already exited an irq handler,
+ * and switched from IRQ stack to process
+ * stack but fp is not yet restored.
+ * Fp still points to IRQ stack, sigh.
+ * For example,
+ * ret_to_user() after irq_handler in el0_irq
+ */
+ frame->sp = bt->stacktop
+ - sizeof(struct arm64_pt_regs)
+ - 0x10;
+ else
+ frame->sp = ext_frame.fp
+ - sizeof(struct arm64_pt_regs);
+ frame->fp = frame->sp;
+ } else {
+ /* We are on IRQ stack */
+
+ ms = machdep->machspec;
+ irq_stack_ptr = ms->irq_stacks[bt->tc->processor]
+ + ms->irq_stack_size - 0x20;
+ if (ext_frame.fp != irq_stack_ptr) {
+ /* Just fake a dummy frame */
+
+ frame->sp = ext_frame.fp
+ - sizeof(struct arm64_pt_regs);
+ frame->fp = frame->sp;
} 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;
+ /*
+ * switch from IRQ stack to process stack
+ */
+
+ frame->sp = GET_STACK_ULONG(irq_stack_ptr + 8);
+ frame->fp = frame->sp;
+
+ /*
+ * Keep a buffer for a while until
+ * displaying the last frame on IRQ stack.
+ * Ugly?
+ */
+ if (bt->flags | BT_FULL)
+ ms->irq_stackbuf = bt->stackbuf;
+
+ arm64_set_process_stack(bt);
}
}
+
+ arm64_gen_hidden_frame(bt, frame->sp, &ext_frame);
}
+unwind_done:
+ if (CRASHDEBUG(1))
+ fprintf(ofp, " nxt fp:%016lx sp:%016lx pc:%016lx\n",
+ frame->fp, frame->sp, frame->pc);
+
return TRUE;
}
-/*
+/*
* A layout of a stack frame in a function looks like:
- *
+ *
* stack grows to lower addresses.
* /|\
* |
@@ -1658,7 +1846,7 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe
*frame)
* | vars |
* old fp +------+
* | |
- *
+ *
* - On function entry, sp is decremented down to new fp.
*
* - and old fp and sp are saved into this stack frame.
@@ -1680,13 +1868,13 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe
*frame)
* sp shows "callee's static local variables", old fp and sp.
*
* Diagram and explanation courtesy of Takahiro Akashi
- */
+ */
static void
arm64_back_trace_cmd(struct bt_info *bt)
{
- struct arm64_stackframe stackframe;
- int level;
+ struct arm64_stackframe stackframe, cur_frame;
+ int level, mode;
ulong exception_frame;
FILE *ofp;
@@ -1708,17 +1896,7 @@ arm64_back_trace_cmd(struct bt_info *bt)
stackframe.fp = GET_STACK_ULONG(bt->bptr - 8);
stackframe.pc = GET_STACK_ULONG(bt->bptr);
stackframe.sp = bt->bptr + 8;
- bt->frameptr = stackframe.sp;
- } else if (bt->hp && bt->hp->esp) {
- if (arm64_on_irq_stack(bt->tc->processor, bt->hp->esp)) {
- arm64_set_irq_stack(bt);
- bt->flags |= BT_IRQSTACK;
- }
- stackframe.fp = GET_STACK_ULONG(bt->hp->esp - 8);
- stackframe.pc = bt->hp->eip ?
- bt->hp->eip : GET_STACK_ULONG(bt->hp->esp);
- stackframe.sp = bt->hp->esp + 8;
- bt->flags &= ~BT_REGS_NOT_FOUND;
+ bt->frameptr = stackframe.fp;
} else {
stackframe.sp = bt->stkptr;
stackframe.pc = bt->instptr;
@@ -1739,8 +1917,14 @@ arm64_back_trace_cmd(struct bt_info *bt)
return;
if (!(bt->flags & BT_KDUMP_ADJUST)) {
- if (bt->flags & BT_USER_SPACE)
- goto complete_user;
+ if (bt->flags & BT_USER_SPACE) {
+ exception_frame = bt->stacktop - USER_EFRAME_OFFSET;
+ arm64_print_exception_frame(bt, exception_frame,
+ USER_MODE, ofp);
+ fprintf(ofp, " #0 [user space]\n");
+
+ return;
+ }
if (DUMPFILE() && is_task_active(bt->task)) {
exception_frame = stackframe.fp - SIZE(pt_regs);
@@ -1750,53 +1934,55 @@ arm64_back_trace_cmd(struct bt_info *bt)
}
}
- level = exception_frame = 0;
- while (1) {
+ for (level = 0;; level++) {
bt->instptr = stackframe.pc;
- switch (arm64_print_stackframe_entry(bt, level, &stackframe, ofp))
- {
- case BACKTRACE_COMPLETE_KERNEL:
- return;
- case BACKTRACE_COMPLETE_USER:
- goto complete_user;
- case BACKTRACE_CONTINUE:
+ /*
+ * Show one-line stackframe info
+ */
+ if (arm64_print_stackframe_entry(bt, level, &stackframe, ofp)
+ == BACKTRACE_COMPLETE_KERNEL)
break;
- }
-
- if (exception_frame) {
- arm64_print_exception_frame(bt, exception_frame, KERNEL_MODE, ofp);
- exception_frame = 0;
- }
- if (!arm64_unwind_frame(bt, &stackframe))
+ cur_frame = stackframe;
+ if (!arm64_unwind_frame(bt, &stackframe, ofp))
break;
- 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);
- }
+ /*
+ * Dump the contents of the current stackframe.
+ * We need to know the next stackframe to determine
+ * the dump range:
+ * <cur_frame.fp:stackframe.fp>
+ */
+ arm64_display_full_frame(bt, &cur_frame, &stackframe);
- if ((bt->flags & BT_IRQSTACK) &&
- !arm64_on_irq_stack(bt->tc->processor, stackframe.sp)) {
- bt->flags &= ~BT_IRQSTACK;
- if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE)
- break;
- }
+ /*
+ * If we are in a normal stackframe, just continue,
+ * otherwise show an exception frame.
+ * Since exception entry code doesn't have a real
+ * stackframe, we fake a dummy frame here.
+ */
+ if (!arm64_in_exp_entry(stackframe.pc))
+ continue;
+ if (!INSTACK(cur_frame.sp, bt))
+ fprintf(ofp, "--- <IRQ stack> ---\n");
- level++;
- }
+ arm64_print_stackframe_entry(bt, ++level, &stackframe, ofp);
+ cur_frame = stackframe;
+ arm64_unwind_frame(bt, &stackframe, ofp);
- if (is_kernel_thread(bt->tc->task))
- return;
+ /*
+ * and don't show the contenxts. Instead,
+ * show an exception frame below
+ */
+ mode = (stackframe.pc < machdep->machspec->userspace_top) ?
+ USER_MODE : KERNEL_MODE;
+ arm64_print_exception_frame(bt, cur_frame.sp, mode, ofp);
-complete_user:
- exception_frame = bt->stacktop - USER_EFRAME_OFFSET;
- arm64_print_exception_frame(bt, exception_frame, USER_MODE, ofp);
- if ((bt->flags & (BT_USER_SPACE|BT_KDUMP_ADJUST)) == BT_USER_SPACE)
- fprintf(ofp, " #0 [user space]\n");
+ if (mode == USER_MODE)
+ break;
+ }
}
static void
@@ -1932,41 +2118,6 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
return FALSE;
}
-static int
-arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp)
-{
- int i;
- ulong stacktop, words, addr;
- ulong *stackbuf;
- char buf[BUFSIZE];
- struct machine_specific *ms = machdep->machspec;
-
- if (bt->flags & BT_FULL) {
- stacktop = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size;
- words = (stacktop - bt->bptr) / sizeof(ulong);
- stackbuf = (ulong *)GETBUF(words * sizeof(ulong));
- readmem(bt->bptr, KVADDR, stackbuf, words * sizeof(long),
- "top of IRQ stack", FAULT_ON_ERROR);
-
- addr = bt->bptr;
- for (i = 0; i < words; i++) {
- if (!(i & 1))
- fprintf(ofp, "%s %lx: ", i ? "\n" : "", addr);
- fprintf(ofp, "%s ", format_stack_entry(bt, buf, stackbuf[i], 0));
- addr += sizeof(ulong);
- }
- fprintf(ofp, "\n");
- FREEBUF(stackbuf);
- }
- fprintf(ofp, "--- <IRQ stack> ---\n");
-
- if (frame->fp == 0)
- return USER_MODE;
-
- arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
- return KERNEL_MODE;
-}
-
static int
arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame)
{
@@ -2047,6 +2198,20 @@ arm64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
}
static void
+arm64_gen_hidden_frame(struct bt_info *bt, ulong sp,
+ struct arm64_stackframe *frame)
+{
+ struct arm64_pt_regs *ptregs;
+
+ ptregs = (struct arm64_pt_regs *)
+ &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(sp))];
+
+ frame->pc = ptregs->pc;
+ frame->fp = ptregs->regs[29];
+ frame->sp = ptregs->sp;
+}
+
+static void
arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *ofp)
{
int i, r, rows, top_reg, is_64_bit;
@@ -2055,10 +2220,16 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int
mode, FILE *o
ulong LR, SP, offset;
char buf[BUFSIZE];
+ if (mode == KERNEL_MODE)
+ fprintf(ofp, "--- <Exception in kernel> ---\n");
+ else
+ fprintf(ofp, "--- <Exception in user> ---\n");
+
if (CRASHDEBUG(1))
fprintf(ofp, "pt_regs: %lx\n", pt_regs);
- regs = (struct arm64_pt_regs
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(pt_regs))];
+ regs = (struct arm64_pt_regs *)
+ &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(pt_regs))];
if ((mode == USER_MODE) && (regs->pstate & PSR_MODE32_BIT)) {
LR = regs->regs[14];
@@ -2130,10 +2301,11 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int
mode, FILE *o
}
if (is_64_bit) {
- fprintf(ofp, "ORIG_X0: %016lx SYSCALLNO: %lx",
- (ulong)regs->orig_x0, (ulong)regs->syscallno);
- if (mode == USER_MODE)
+ if (mode == USER_MODE) {
+ fprintf(ofp, "ORIG_X0: %016lx SYSCALLNO: %lx",
+ (ulong)regs->orig_x0, (ulong)regs->syscallno);
fprintf(ofp, " PSTATE: %08lx", (ulong)regs->pstate);
+ }
fprintf(ofp, "\n");
}
diff --git a/defs.h b/defs.h
index d6f719c..f7ea5a0 100644
--- a/defs.h
+++ b/defs.h
@@ -3058,8 +3058,14 @@ struct machine_specific {
ulong kernel_flags;
ulong irq_stack_size;
ulong *irq_stacks;
+ char *irq_stackbuf;
ulong __irqentry_text_start;
ulong __irqentry_text_end;
+ /* for exception vector code */
+ ulong exp_entry1_start;
+ ulong exp_entry1_end;
+ ulong exp_entry2_start;
+ ulong exp_entry2_end;
/* only needed for v4.6 or later kernel */
ulong kimage_voffset;
ulong kimage_text;
--
2.9.0