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 <ben.dooks@codethink.co.uk>
Tested-by: Leo Yu-Chi Liang <ycliang@andestech.com>
This commit is contained in:
Ben Dooks
2023-09-05 13:12:53 +01:00
committed by Leo Yu-Chi Liang
parent 069d07396e
commit e4f69492ad
4 changed files with 60 additions and 0 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 ...

View File

@@ -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");