[Crash-utility] arm64: "bt -f" output

AKASHI Takahiro takahiro.akashi at linaro.org
Wed Jun 8 04:21:39 UTC 2016


Dave,

When I looked at the output from "bt -f" command, I found that stack dump
starts from frame.sp in arm64_print_stackframe_entry().
Usage of stack frames on arm64 is a bit different from that on x86, and
using frame.fp is, I believe, much useful (and accurate) for crash users.
See my patch attached below.

Details:
A layout of a stack frame in a function looks like:

         stack grows to lower addresses.
           /|\
            |
         |      |
new sp   +------+ <---
         |dyn   |   |
         | vars |   |
new fp   +- - - +   |
         |old fp|   | a function's stack frame
         |old lr|   |
         |static|   |
         |  vars|   |
old sp   +------+ <---
         |dyn   |
         | vars |
old fp   +------+
         |      |

* On function entry, sp is decremented down to new fp.
* and old fp and sp are saved into this stack frame.
  "Static" local variables are allocated at the same time.
* Later on, "dynamic" local variables may be allocated on a stack.
  But those dynamic variables are rarely used in the kernel image,
  and, as a matter of fact, sp is equal to fp in almost all functions.
  (not 100% though.)

* Currently, sp is determined in arm64_unwind_frame() by
       sp = a callee's fp + 0x10
  where 0x10 stands for a saved area for fp and sp
* As you can see, however, this calculated sp still points to the top of
  callee's static local variables and doesn't match with a *real* sp.
* So, generally, dumping a stack from this calculated sp to the next frame's
  sp shows "callee's static local variables", old fp and sp.

Confused?
Probably you will be able to understand more easily by seeing an example
from my vmlinux/vmcore cases:

=== crash with my patch ===
crash> bt -f 1324
PID: 1324   TASK: ffff80002018be80  CPU: 2   COMMAND: "dhry"
ffff800022f6ae08: ffff00000812ae44 (crash_save_cpu on IRQ stack)
    ffff800022f6ae10: ffff800022f74e00 ffff800020107ed0
    ffff800022f6ae20: 0000000000000000 ffff800020107ed0
    ffff800022f6ae30: ffff000008a26800 0000000000000003
    ffff800022f6ae40: 0000018800000005 0000000000000001
 #0 [ffff800022f6ae50] crash_save_cpu at ffff00000812ae44
    ffff800022f6ae50: ffff800022f6b010 ffff00000808e718
                        #1's fp           #1's lr (=handle_IPI)
    ffff800022f6ae60: ffff000008bce000 0000000000000002 -----
    ffff800022f6ae70: ffff800022f6ae90 0000000000000000   |
    ffff800022f6ae80: ffff800000000000 0000000000000000   |
    ffff800022f6ae90: 0000000000000000 0000000000000000   |local variables
    ...                                                   | including a big
    ffff800022f6afd0: 0000000000000000 0000000000000000   |"struct elf_prsatus"
    ffff800022f6afe0: ffff800022f6aff0 ffff00000808a820   |
    ffff800022f6aff0: ffff800022f6b010 ffff00000808e758   |
    ffff800022f6b000: ffff000008bce000 0000000000000000 -----
 #1 [ffff800022f6b010] handle_IPI at ffff00000808e718
    ffff800022f6b010: ffff800022f6b040 ffff0000080815f8
    ffff800022f6b020: 0000000000000003 0000000000001fff
    ffff800022f6b030: ffff800020107ed0 ffff000008e60c54
 #2 [ffff800022f6b040] gic_handle_irq at ffff0000080815f8
    ffff800022f6b040: ffff800022f6b080 ffff000008084c4c
== crash(master branch) ===
crash.dave> bt -f 1324
PID: 1324   TASK: ffff80002018be80  CPU: 2   COMMAND: "dhry"
ffff800022f6ae08: ffff00000812ae44 (crash_save_cpu on IRQ stack)
 #0 [ffff800022f6ae10] crash_save_cpu at ffff00000812ae44
    ffff800022f6ae10: ffff800022f74e00 ffff800020107ed0 -----
    ffff800022f6ae20: 0000000000000000 ffff800020107ed0   |local variables
    ffff800022f6ae30: ffff000008a26800 0000000000000003   | of callee(*)
    ffff800022f6ae40: 0000018800000005 0000000000000001 -----
    ffff800022f6ae50: ffff800022f6b010 ffff00000808e718 <= *real* stack frame
 #1 [ffff800022f6ae60] handle_IPI at ffff00000808e718      of crash_save_cpu()
    ffff800022f6ae60: ffff000008bce000 0000000000000002    starts here.
    ffff800022f6ae70: ffff800022f6ae90 0000000000000000
    ffff800022f6ae80: ffff800000000000 0000000000000000
    ffff800022f6ae90: 0000000000000000 0000000000000000
    ffff800022f6aea0: 0000000000000000 000000000000052c
    ffff800022f6aeb0: 0000000000000000 0000000000000000
    ...
    ffff800022f6afa0: ffff800022f6afc0 0000000000000000
    ffff800022f6afb0: ffff800022f6afe0 ffff000008675850
    ffff800022f6afc0: 0000000000402138 0000000000000000
    ffff800022f6afd0: 0000000000000000 0000000000000000
    ffff800022f6afe0: ffff800022f6aff0 ffff00000808a820
    ffff800022f6aff0: ffff800022f6b010 ffff00000808e758
    ffff800022f6b000: ffff000008bce000 0000000000000000
    ffff800022f6b010: ffff800022f6b040 ffff0000080815f8
 #2 [ffff800022f6b020] gic_handle_irq at ffff0000080815f8
    ffff800022f6b020: 0000000000000003 0000000000001fff
    ffff800022f6b030: ffff800020107ed0 ffff000008e60c54
    ffff800022f6b040: ffff800022f6b080 ffff000008084c4c
=== END ===
    (*) append_elf_note()

Thanks,
-Takahiro AKASHI

======8<======
>From b3ca69ace916a5c233ce937954da887ba5487e50 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] arm64: dump a stack frame based on fp

Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
 arm64.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/arm64.c b/arm64.c
index bdea79c..22f93a2 100644
--- a/arm64.c
+++ b/arm64.c
@@ -1508,12 +1508,12 @@ arm64_print_stackframe_entry(struct bt_info *bt, int level, struct arm64_stackfr
         }
 
 	if (bt->flags & BT_FULL) {
-		arm64_display_full_frame(bt, frame->sp);
-		bt->frameptr = frame->sp;
+		arm64_display_full_frame(bt, frame->fp);
+		bt->frameptr = frame->fp;
 	}
 
         fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level,
-                frame->sp, name_plus_offset ? name_plus_offset : name, frame->pc);
+                frame->fp, name_plus_offset ? name_plus_offset : name, frame->pc);
 
 	if (BT_REFERENCE_CHECK(bt))
 		arm64_do_bt_reference_check(bt, frame->pc, name);
@@ -1571,12 +1571,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;
 
@@ -1613,7 +1611,7 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
 				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;
+				bt->bptr = fp;
 				if (CRASHDEBUG(1))
 					error(INFO, 
 					    "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx  pc: %lx\n",
@@ -2004,8 +2002,11 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *o
 	ulong LR, SP, offset;
 	char buf[BUFSIZE];
 
+#if 0 /* FIXME? */
 	if (bt->flags & BT_FULL)
 		arm64_display_full_frame(bt, pt_regs);
+}
+#endif
 
 	if (CRASHDEBUG(1)) 
 		fprintf(ofp, "pt_regs: %lx\n", pt_regs);
-- 
2.8.1




More information about the Crash-utility mailing list