[Concept,02/10] backtrace: Add a library to access the backtrace
Commit Message
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
new file mode 100644
@@ -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 */
@@ -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
@@ -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
new file mode 100644
@@ -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;
+}