Changes in v2: * Basically moved arm64_print_stackframe_entry() after arm64_unwind_frame() in arm64_back_trace_cmd() to make the output consistent with the format on x86 Then, we had to calculate the end address of a stack frame, frame_top, for particular cases. -Takahiro AKASHI ======8<====== >From d8683645599a238578a0f586af563bc9f847d52c Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro <takahiro.akashi@xxxxxxxxxx> Date: Wed, 8 Jun 2016 11:14:22 +0900 Subject: [PATCH v2] arm64: dump a stack frame based on fp Signed-off-by: AKASHI Takahiro <takahiro.akashi@xxxxxxxxxx> --- arm64.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- defs.h | 5 +++ 2 files changed, 110 insertions(+), 35 deletions(-) diff --git a/arm64.c b/arm64.c index bdea79c..7b5b394 100644 --- a/arm64.c +++ b/arm64.c @@ -43,9 +43,10 @@ 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 int arm64_print_stackframe_entry(struct bt_info *, int, struct arm64_stackframe *, 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 int arm64_get_dumpfile_stackframe(struct bt_info *, struct arm64_stackframe *); @@ -597,6 +598,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: "); @@ -1283,6 +1288,16 @@ arm64_stackframe_init(void) 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)) && (sp2 = kernel_symbol_search("crash_save_cpu")) && @@ -1484,18 +1499,54 @@ arm64_in_exception_text(ulong ptr) return FALSE; } +static int +arm64_in_exp_entry(ulong addr) +{ + struct machine_specific *ms; + + ms = machdep->machspec; + if ((ms->exp_entry1_start <= addr) && (addr < ms->exp_entry1_end)) + return TRUE; + 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) +arm64_print_stackframe_entry(struct bt_info *bt, int level, struct arm64_stackframe *frame, struct arm64_stackframe *caller_frame, FILE *ofp) { char *name, *name_plus_offset; ulong symbol_offset; struct syment *sp; struct load_module *lm; char buf[BUFSIZE]; + unsigned long frame_top; + + if (caller_frame->fp) { +#if 0 /* FIXME: Need to debug here */ + if (arm64_in_exp_entry(caller_frame->pc)) + frame_top = caller_frame->fp - sizeof(struct arm64_pt_regs); + else +#endif + frame_top = caller_frame->fp; + } else if (frame->fp && !arm64_in_exp_entry(frame->pc)) + frame_top = bt->stacktop - USER_EFRAME_OFFSET; + else + frame_top = bt->stacktop - 0x10; + + if (CRASHDEBUG(1)) { + fprintf(ofp, " cur sp:%016lx fp:%016lx pc:%016lx\n", + frame->sp, frame->fp, frame->pc); + fprintf(ofp, " nxt sp:%016lx fp:%016lx pc:%016lx\n", + caller_frame->sp, caller_frame->fp, caller_frame->pc); + + fprintf(ofp, " frame: <%lx-%lx> check(%d, %d)\n", + bt->frameptr, frame_top, + INSTACK(frame_top, bt), INSTACK(bt->frameptr, bt)); + } name = closest_symbol(frame->pc); name_plus_offset = NULL; @@ -1507,13 +1558,16 @@ 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) { - arm64_display_full_frame(bt, frame->sp); - bt->frameptr = frame->sp; - } + if (bt->flags & BT_FULL) + arm64_display_full_frame(bt, frame_top); + bt->frameptr = frame_top; fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level, - frame->sp, name_plus_offset ? name_plus_offset : name, frame->pc); +#if 1 /* FIXME */ + (frame->fp ? : frame->sp), name_plus_offset ? name_plus_offset : name, frame->pc); +#else + frame->fp, name_plus_offset ? name_plus_offset : name, frame->pc); +#endif if (BT_REFERENCE_CHECK(bt)) arm64_do_bt_reference_check(bt, frame->pc, name); @@ -1571,12 +1625,10 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) { unsigned long high, low, fp; unsigned long stack_mask; - unsigned long irq_stack_ptr, orig_sp, sp_in; + unsigned long irq_stack_ptr, orig_sp; struct arm64_pt_regs *ptregs; struct machine_specific *ms; - sp_in = frame->sp; - stack_mask = (unsigned long)(ARM64_STACK_SIZE) - 1; fp = frame->fp; @@ -1612,8 +1664,17 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) 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 = sp_in; + + /* + * if frame->fp == 0, ptregs->pc is a pc + * where an exception in user mode was taken. + * So don't update frame->pc since we have + * a pseudo stack frame for exception entry. + */ + if (frame->fp) + frame->pc = ptregs->pc; + + bt->bptr = fp; if (CRASHDEBUG(1)) error(INFO, "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n", @@ -1634,10 +1695,11 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) static void arm64_back_trace_cmd(struct bt_info *bt) { - struct arm64_stackframe stackframe; + struct arm64_stackframe stackframe, cur_frame; int level; ulong exception_frame; FILE *ofp; + int end_stack = 0; ofp = BT_REFERENCE_CHECK(bt) ? pc->nullfp : fp; @@ -1657,7 +1719,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; + bt->frameptr = stackframe.fp; } else if (bt->hp && bt->hp->esp) { if (arm64_on_irq_stack(bt->tc->processor, bt->hp->esp)) { arm64_set_irq_stack(bt); @@ -1703,23 +1765,9 @@ arm64_back_trace_cmd(struct bt_info *bt) while (1) { 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: - break; - } - - if (exception_frame) { - arm64_print_exception_frame(bt, exception_frame, KERNEL_MODE, ofp); - exception_frame = 0; - } - + cur_frame = stackframe; if (!arm64_unwind_frame(bt, &stackframe)) - break; + end_stack = 1; if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) { if (!(bt->flags & BT_IRQSTACK) || @@ -1731,9 +1779,30 @@ arm64_back_trace_cmd(struct bt_info *bt) !arm64_on_irq_stack(bt->tc->processor, stackframe.sp)) { bt->flags &= ~BT_IRQSTACK; if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE) - break; + end_stack = 1; + else + arm64_print_exception_frame(bt, stackframe.sp, + KERNEL_MODE, ofp); + + /* Next, we will display a process stack. */ + bt->frameptr = stackframe.sp; } + switch (arm64_print_stackframe_entry(bt, level, &cur_frame, &stackframe, ofp)) + { + case BACKTRACE_COMPLETE_KERNEL: + return; + case BACKTRACE_CONTINUE: + break; + } + + if (end_stack) + break; + + if (arm64_in_exp_entry(cur_frame.pc) && exception_frame) { + arm64_print_exception_frame(bt, exception_frame, KERNEL_MODE, ofp); + exception_frame = 0; + } level++; } @@ -1912,7 +1981,6 @@ 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); return KERNEL_MODE; } @@ -2004,8 +2072,10 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *o ulong LR, SP, offset; char buf[BUFSIZE]; - if (bt->flags & BT_FULL) - arm64_display_full_frame(bt, pt_regs); + 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); diff --git a/defs.h b/defs.h index d6f719c..90d8406 100644 --- a/defs.h +++ b/defs.h @@ -3060,6 +3060,11 @@ struct machine_specific { ulong *irq_stacks; 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.8.1 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility