[Crash-utility] [PATCH v2] arm64: dump a stack frame based on fp

AKASHI Takahiro takahiro.akashi at linaro.org
Mon Jun 13 07:13:31 UTC 2016


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 at linaro.org>
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 at linaro.org>
---
 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




More information about the Crash-utility mailing list