summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Dooks <[email protected]>2023-09-05 13:12:53 +0100
committerLeo Yu-Chi Liang <[email protected]>2024-04-09 11:29:38 +0800
commite4f69492adfdd1c72c0d2d031fe2606efe125773 (patch)
treed92bd265d0469269fad8dec0b6817f953dcb14aa
parent069d07396e30aa9be396c1dd3fc158ac199e6843 (diff)
riscv: add backtrace support
When debugging, it is useful to have a backtrace to find out what is in the call stack as the previous function (RA) may not have been the culprit. Since this adds size to the build, do not add it by default and avoid putting it in the SPL build if not needed. Signed-off-by: Ben Dooks <[email protected]> Tested-by: Leo Yu-Chi Liang <[email protected]>
-rw-r--r--arch/riscv/Kconfig20
-rw-r--r--arch/riscv/Makefile4
-rw-r--r--arch/riscv/cpu/start.S1
-rw-r--r--arch/riscv/lib/interrupts.c35
4 files changed, 60 insertions, 0 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 6c26f91f166..1819db1e256 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -119,6 +119,26 @@ config ARCH_RV64I
endchoice
+config FRAMEPOINTER
+ bool "Build with frame pointer for stack unwinding"
+ help
+ Choose this option to use the frame pointer so the stack can be
+ unwound if needed. This is useful for tracing where faults came
+ from as the source may be several functions back
+
+ If you say Y here, then the code size will be increased due to
+ having to store the fp.
+
+config SPL_FRAMEPOINTER
+ bool "Build SPL with frame pointer for stack unwinding"
+ help
+ Choose this option to use the frame pointer so the stack can be
+ unwound if needed. This is useful for tracing where faults came
+ from as the source may be several functions back
+
+ If you say Y here, then the code size will be increased due to
+ having to store the fp.
+
choice
prompt "Code Model"
default CMODEL_MEDLOW
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index b3ef87078b5..c36a8533e0f 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -48,6 +48,10 @@ endif
ARCH_FLAGS = -march=$(RISCV_MARCH) -mabi=$(ABI) \
-mcmodel=$(CMODEL)
+ifeq ($(CONFIG_$(SPL_)FRAMEPOINTER),y)
+ ARCH_FLAGS += -fno-omit-frame-pointer
+endif
+
PLATFORM_CPPFLAGS += $(ARCH_FLAGS)
CFLAGS_EFI += $(ARCH_FLAGS)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 6cecadfac56..a9e19356928 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -418,6 +418,7 @@ call_board_init_r:
*/
mv a0, s3 /* gd_t */
mv a1, s4 /* dest_addr */
+ mv s0, zero /* fp == NULL */
/*
* jump to it ...
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index a26ccc721fd..7350e2ced85 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -60,6 +60,40 @@ static void show_regs(struct pt_regs *regs)
#endif
}
+#if defined(CONFIG_FRAMEPOINTER) || defined(CONFIG_SPL_FRAMEPOINTER)
+static void show_backtrace(struct pt_regs *regs)
+{
+ uintptr_t *fp = (uintptr_t *)regs->s0;
+ unsigned count = 0;
+ ulong ra;
+
+ printf("backtrace:\n");
+
+ /* there are a few entry points where the s0 register is
+ * set to gd, so to avoid changing those, just abort if
+ * the value is the same */
+ while (fp != NULL && fp != (uintptr_t *)gd) {
+ ra = fp[-1];
+ printf("backtrace %2d: FP: " REG_FMT " RA: " REG_FMT,
+ count, (ulong)fp, ra);
+
+ if (gd && gd->flags & GD_FLG_RELOC)
+ printf(" - RA: " REG_FMT " reloc adjusted\n",
+ ra - gd->reloc_off);
+ else
+ printf("\n");
+
+ fp = (uintptr_t *)fp[-2];
+ count++;
+ }
+}
+#else
+static void show_backtrace(struct pt_regs *regs)
+{
+ printf("No backtrace support enabled\n");
+}
+#endif
+
/**
* instr_len() - get instruction length
*
@@ -131,6 +165,7 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
epc - gd->reloc_off, regs->ra - gd->reloc_off);
show_regs(regs);
+ show_backtrace(regs);
show_code(epc);
show_efi_loaded_images(epc);
panic("\n");