From: Simon Glass <simon.glass@canonical.com> Provide an API to access the backtrace, in an arch-neutral way. The backtrace can be retrieved, examined and printed. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- include/backtrace.h | 72 +++++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 8 +++++ lib/Makefile | 1 + lib/backtrace.c | 40 +++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 include/backtrace.h create mode 100644 lib/backtrace.c diff --git a/include/backtrace.h b/include/backtrace.h new file mode 100644 index 00000000000..eece61e4d9a --- /dev/null +++ b/include/backtrace.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Backtrace support + * + * Copyright 2025 Canonical Ltd + * Written by Simon Glass <simon.glass@canonical.com> + */ + +#ifndef __BACKTRACE_H +#define __BACKTRACE_H + +#define BACKTRACE_MAX 100 +#define BACKTRACE_SYM_SIZE 128 +#define BACKTRACE_BUFSZ (BACKTRACE_MAX * BACKTRACE_SYM_SIZE) + +/** + * struct backtrace_ctx - context for backtrace operations + * + * @addrs: array of return addresses + * @syms: array of symbol strings (NULL until backtrace_get_syms() called) + * @count: number of entries in addrs/syms arrays + */ +struct backtrace_ctx { + void *addrs[BACKTRACE_MAX]; + char *syms[BACKTRACE_MAX]; + unsigned int count; +}; + +/** + * backtrace_init() - collect a backtrace + * + * Collect backtrace addresses into the context. Call backtrace_uninit() when + * done with the context. + * + * @ctx: context to fill + * @skip: number of stack frames to skip (0 to include backtrace_init itself) + * Return: number of addresses collected, or -ve on error (e.g. -ENOSYS) + */ +int backtrace_init(struct backtrace_ctx *ctx, unsigned int skip); + +/** + * backtrace_get_syms() - get symbol strings for a backtrace + * + * Convert the addresses in the context to symbol strings. The strings are + * stored in ctx->syms[]. The caller must provide a buffer of sufficient size. + * + * @ctx: context with addresses from backtrace_init() + * @buf: buffer to use for string storage + * @size: size of buffer in bytes + * Return: 0 if OK, -ENOSPC if buffer too small + */ +int backtrace_get_syms(struct backtrace_ctx *ctx, char *buf, int size); + +/** + * backtrace_uninit() - free backtrace resources + * + * Free any memory allocated in the context. + * + * @ctx: context to free + */ +void backtrace_uninit(struct backtrace_ctx *ctx); + +/** + * backtrace_show() - print a backtrace + * + * Print a backtrace of the current call stack. + * + * Return: 0 if OK, -ve on error + */ +int backtrace_show(void); + +#endif /* __BACKTRACE_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 662b1a44d45..d7f791f77f3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -28,6 +28,14 @@ config PHYSMEM Enable this to access this basic support, which only supports clearing the memory. +config BACKTRACE + bool "Enable backtrace support" + depends on SANDBOX + help + Enables support for printing a backtrace showing the current call + stack. This is currently only available on sandbox. The backtrace + command can be used to print the backtrace. + config BCH bool "Enable Software based BCH ECC" help diff --git a/lib/Makefile b/lib/Makefile index 5cbf3071f96..b696e81c496 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -147,6 +147,7 @@ obj-$(CONFIG_TRACE) += trace.o obj-$(CONFIG_LIB_UUID) += uuid.o obj-$(CONFIG_LIB_RAND) += rand.o obj-y += panic.o +obj-$(CONFIG_BACKTRACE) += backtrace.o ifeq ($(CONFIG_XPL_BUILD),y) # SPL U-Boot may use full-printf, tiny-printf or none at all diff --git a/lib/backtrace.c b/lib/backtrace.c new file mode 100644 index 00000000000..e3d93b80b8a --- /dev/null +++ b/lib/backtrace.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Stack-backtrace support + * + * Copyright 2025 Canonical Ltd + * Written by Simon Glass <simon.glass@canonical.com> + */ + +#include <backtrace.h> +#include <stdio.h> + +int backtrace_show(void) +{ + char buf[BACKTRACE_BUFSZ]; + struct backtrace_ctx ctx; + uint i; + int ret; + + ret = backtrace_init(&ctx, 1); + if (ret < 0) + return ret; + + ret = backtrace_get_syms(&ctx, buf, sizeof(buf)); + if (ret) { + backtrace_uninit(&ctx); + return ret; + } + + printf("backtrace: %d addresses\n", ctx.count); + for (i = 0; i < ctx.count; i++) { + if (ctx.syms[i]) + printf(" %s\n", ctx.syms[i]); + else + printf(" %p\n", ctx.addrs[i]); + } + + backtrace_uninit(&ctx); + + return 0; +} -- 2.43.0